iPXE
efi_block.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2016 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 block device protocols
00030  *
00031  */
00032 
00033 #include <stddef.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <errno.h>
00037 #include <ipxe/refcnt.h>
00038 #include <ipxe/list.h>
00039 #include <ipxe/uri.h>
00040 #include <ipxe/interface.h>
00041 #include <ipxe/blockdev.h>
00042 #include <ipxe/xfer.h>
00043 #include <ipxe/open.h>
00044 #include <ipxe/retry.h>
00045 #include <ipxe/timer.h>
00046 #include <ipxe/process.h>
00047 #include <ipxe/sanboot.h>
00048 #include <ipxe/iso9660.h>
00049 #include <ipxe/acpi.h>
00050 #include <ipxe/efi/efi.h>
00051 #include <ipxe/efi/Protocol/BlockIo.h>
00052 #include <ipxe/efi/Protocol/SimpleFileSystem.h>
00053 #include <ipxe/efi/Protocol/AcpiTable.h>
00054 #include <ipxe/efi/efi_driver.h>
00055 #include <ipxe/efi/efi_strings.h>
00056 #include <ipxe/efi/efi_snp.h>
00057 #include <ipxe/efi/efi_utils.h>
00058 #include <ipxe/efi/efi_block.h>
00059 
00060 /** ACPI table protocol protocol */
00061 static EFI_ACPI_TABLE_PROTOCOL *acpi;
00062 EFI_REQUEST_PROTOCOL ( EFI_ACPI_TABLE_PROTOCOL, &acpi );
00063 
00064 /** Boot filename */
00065 static wchar_t efi_block_boot_filename[] = EFI_REMOVABLE_MEDIA_FILE_NAME;
00066 
00067 /** iPXE EFI block device vendor device path GUID */
00068 #define IPXE_BLOCK_DEVICE_PATH_GUID                                     \
00069         { 0x8998b594, 0xf531, 0x4e87,                                   \
00070           { 0x8b, 0xdf, 0x8f, 0x88, 0x54, 0x3e, 0x99, 0xd4 } }
00071 
00072 /** iPXE EFI block device vendor device path GUID */
00073 static EFI_GUID ipxe_block_device_path_guid
00074         = IPXE_BLOCK_DEVICE_PATH_GUID;
00075 
00076 /** An iPXE EFI block device vendor device path */
00077 struct efi_block_vendor_path {
00078         /** Generic vendor device path */
00079         VENDOR_DEVICE_PATH vendor;
00080         /** Block device URI */
00081         CHAR16 uri[0];
00082 } __attribute__ (( packed ));
00083 
00084 /** EFI SAN device private data */
00085 struct efi_block_data {
00086         /** SAN device */
00087         struct san_device *sandev;
00088         /** EFI handle */
00089         EFI_HANDLE handle;
00090         /** Media descriptor */
00091         EFI_BLOCK_IO_MEDIA media;
00092         /** Block I/O protocol */
00093         EFI_BLOCK_IO_PROTOCOL block_io;
00094         /** Device path protocol */
00095         EFI_DEVICE_PATH_PROTOCOL *path;
00096 };
00097 
00098 /**
00099  * Read from or write to EFI block device
00100  *
00101  * @v sandev            SAN device
00102  * @v lba               Starting LBA
00103  * @v data              Data buffer
00104  * @v len               Size of buffer
00105  * @v sandev_rw         SAN device read/write method
00106  * @ret rc              Return status code
00107  */
00108 static int efi_block_rw ( struct san_device *sandev, uint64_t lba,
00109                           void *data, size_t len,
00110                           int ( * sandev_rw ) ( struct san_device *sandev,
00111                                                 uint64_t lba, unsigned int count,
00112                                                 userptr_t buffer ) ) {
00113         struct efi_block_data *block = sandev->priv;
00114         unsigned int count;
00115         int rc;
00116 
00117         /* Sanity check */
00118         count = ( len / block->media.BlockSize );
00119         if ( ( count * block->media.BlockSize ) != len ) {
00120                 DBGC ( sandev, "EFIBLK %#02x impossible length %#zx\n",
00121                        sandev->drive, len );
00122                 return -EINVAL;
00123         }
00124 
00125         /* Read from / write to block device */
00126         if ( ( rc = sandev_rw ( sandev, lba, count,
00127                                 virt_to_user ( data ) ) ) != 0 ) {
00128                 DBGC ( sandev, "EFIBLK %#02x I/O failed: %s\n",
00129                        sandev->drive, strerror ( rc ) );
00130                 return rc;
00131         }
00132 
00133         return 0;
00134 }
00135 
00136 /**
00137  * Reset EFI block device
00138  *
00139  * @v block_io          Block I/O protocol
00140  * @v verify            Perform extended verification
00141  * @ret efirc           EFI status code
00142  */
00143 static EFI_STATUS EFIAPI efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *block_io,
00144                                               BOOLEAN verify __unused ) {
00145         struct efi_block_data *block =
00146                 container_of ( block_io, struct efi_block_data, block_io );
00147         struct san_device *sandev = block->sandev;
00148         int rc;
00149 
00150         DBGC2 ( sandev, "EFIBLK %#02x reset\n", sandev->drive );
00151         efi_snp_claim();
00152         rc = sandev_reset ( sandev );
00153         efi_snp_release();
00154         return EFIRC ( rc );
00155 }
00156 
00157 /**
00158  * Read from EFI block device
00159  *
00160  * @v block_io          Block I/O protocol
00161  * @v media             Media identifier
00162  * @v lba               Starting LBA
00163  * @v len               Size of buffer
00164  * @v data              Data buffer
00165  * @ret efirc           EFI status code
00166  */
00167 static EFI_STATUS EFIAPI
00168 efi_block_io_read ( EFI_BLOCK_IO_PROTOCOL *block_io, UINT32 media __unused,
00169                     EFI_LBA lba, UINTN len, VOID *data ) {
00170         struct efi_block_data *block =
00171                 container_of ( block_io, struct efi_block_data, block_io );
00172         struct san_device *sandev = block->sandev;
00173         int rc;
00174 
00175         DBGC2 ( sandev, "EFIBLK %#02x read LBA %#08llx to %p+%#08zx\n",
00176                 sandev->drive, lba, data, ( ( size_t ) len ) );
00177         efi_snp_claim();
00178         rc = efi_block_rw ( sandev, lba, data, len, sandev_read );
00179         efi_snp_release();
00180         return EFIRC ( rc );
00181 }
00182 
00183 /**
00184  * Write to EFI block device
00185  *
00186  * @v block_io          Block I/O protocol
00187  * @v media             Media identifier
00188  * @v lba               Starting LBA
00189  * @v len               Size of buffer
00190  * @v data              Data buffer
00191  * @ret efirc           EFI status code
00192  */
00193 static EFI_STATUS EFIAPI
00194 efi_block_io_write ( EFI_BLOCK_IO_PROTOCOL *block_io, UINT32 media __unused,
00195                      EFI_LBA lba, UINTN len, VOID *data ) {
00196         struct efi_block_data *block =
00197                 container_of ( block_io, struct efi_block_data, block_io );
00198         struct san_device *sandev = block->sandev;
00199         int rc;
00200 
00201         DBGC2 ( sandev, "EFIBLK %#02x write LBA %#08llx from %p+%#08zx\n",
00202                 sandev->drive, lba, data, ( ( size_t ) len ) );
00203         efi_snp_claim();
00204         rc = efi_block_rw ( sandev, lba, data, len, sandev_write );
00205         efi_snp_release();
00206         return EFIRC ( rc );
00207 }
00208 
00209 /**
00210  * Flush data to EFI block device
00211  *
00212  * @v block_io          Block I/O protocol
00213  * @ret efirc           EFI status code
00214  */
00215 static EFI_STATUS EFIAPI
00216 efi_block_io_flush ( EFI_BLOCK_IO_PROTOCOL *block_io ) {
00217         struct efi_block_data *block =
00218                 container_of ( block_io, struct efi_block_data, block_io );
00219         struct san_device *sandev = block->sandev;
00220 
00221         DBGC2 ( sandev, "EFIBLK %#02x flush\n", sandev->drive );
00222 
00223         /* Nothing to do */
00224         return 0;
00225 }
00226 
00227 /**
00228  * Connect all possible drivers to EFI block device
00229  *
00230  * @v sandev            SAN device
00231  */
00232 static void efi_block_connect ( struct san_device *sandev ) {
00233         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00234         struct efi_block_data *block = sandev->priv;
00235         EFI_STATUS efirc;
00236         int rc;
00237 
00238         /* Try to connect all possible drivers to this block device */
00239         if ( ( efirc = bs->ConnectController ( block->handle, NULL,
00240                                                NULL, 1 ) ) != 0 ) {
00241                 rc = -EEFI ( efirc );
00242                 DBGC ( sandev, "EFIBLK %#02x could not connect drivers: %s\n",
00243                        sandev->drive, strerror ( rc ) );
00244                 /* May not be an error; may already be connected */
00245         }
00246         DBGC2 ( sandev, "EFIBLK %#02x supports protocols:\n", sandev->drive );
00247         DBGC2_EFI_PROTOCOLS ( sandev, block->handle );
00248 }
00249 
00250 /**
00251  * Hook EFI block device
00252  *
00253  * @v drive             Drive number
00254  * @v uris              List of URIs
00255  * @v count             Number of URIs
00256  * @v flags             Flags
00257  * @ret drive           Drive number, or negative error
00258  */
00259 static int efi_block_hook ( unsigned int drive, struct uri **uris,
00260                             unsigned int count, unsigned int flags ) {
00261         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00262         EFI_DEVICE_PATH_PROTOCOL *end;
00263         struct efi_block_vendor_path *vendor;
00264         struct efi_snp_device *snpdev;
00265         struct san_device *sandev;
00266         struct efi_block_data *block;
00267         size_t prefix_len;
00268         size_t uri_len;
00269         size_t vendor_len;
00270         size_t len;
00271         char *uri_buf;
00272         EFI_STATUS efirc;
00273         int rc;
00274 
00275         /* Sanity check */
00276         if ( ! count ) {
00277                 DBG ( "EFIBLK has no URIs\n" );
00278                 rc = -ENOTTY;
00279                 goto err_no_uris;
00280         }
00281 
00282         /* Find an appropriate parent device handle */
00283         snpdev = last_opened_snpdev();
00284         if ( ! snpdev ) {
00285                 DBG ( "EFIBLK could not identify SNP device\n" );
00286                 rc = -ENODEV;
00287                 goto err_no_snpdev;
00288         }
00289 
00290         /* Calculate length of private data */
00291         prefix_len = efi_devpath_len ( snpdev->path );
00292         uri_len = format_uri ( uris[0], NULL, 0 );
00293         vendor_len = ( sizeof ( *vendor ) +
00294                        ( ( uri_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ) );
00295         len = ( sizeof ( *block ) + uri_len + 1 /* NUL */ + prefix_len +
00296                 vendor_len + sizeof ( *end ) );
00297 
00298         /* Allocate and initialise structure */
00299         sandev = alloc_sandev ( uris, count, len );
00300         if ( ! sandev ) {
00301                 rc = -ENOMEM;
00302                 goto err_alloc;
00303         }
00304         block = sandev->priv;
00305         block->sandev = sandev;
00306         block->media.MediaPresent = 1;
00307         block->media.LogicalBlocksPerPhysicalBlock = 1;
00308         block->block_io.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
00309         block->block_io.Media = &block->media;
00310         block->block_io.Reset = efi_block_io_reset;
00311         block->block_io.ReadBlocks = efi_block_io_read;
00312         block->block_io.WriteBlocks = efi_block_io_write;
00313         block->block_io.FlushBlocks = efi_block_io_flush;
00314         uri_buf = ( ( ( void * ) block ) + sizeof ( *block ) );
00315         block->path = ( ( ( void * ) uri_buf ) + uri_len + 1 /* NUL */ );
00316 
00317         /* Construct device path */
00318         memcpy ( block->path, snpdev->path, prefix_len );
00319         vendor = ( ( ( void * ) block->path ) + prefix_len );
00320         vendor->vendor.Header.Type = HARDWARE_DEVICE_PATH;
00321         vendor->vendor.Header.SubType = HW_VENDOR_DP;
00322         vendor->vendor.Header.Length[0] = ( vendor_len & 0xff );
00323         vendor->vendor.Header.Length[1] = ( vendor_len >> 8 );
00324         memcpy ( &vendor->vendor.Guid, &ipxe_block_device_path_guid,
00325                  sizeof ( vendor->vendor.Guid ) );
00326         format_uri ( uris[0], uri_buf, ( uri_len + 1 /* NUL */ ) );
00327         efi_snprintf ( vendor->uri, ( uri_len + 1 /* NUL */ ), "%s", uri_buf );
00328         end = ( ( ( void * ) vendor ) + vendor_len );
00329         end->Type = END_DEVICE_PATH_TYPE;
00330         end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
00331         end->Length[0] = sizeof ( *end );
00332         DBGC ( sandev, "EFIBLK %#02x has device path %s\n",
00333                drive, efi_devpath_text ( block->path ) );
00334 
00335         /* Register SAN device */
00336         if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
00337                 DBGC ( sandev, "EFIBLK %#02x could not register: %s\n",
00338                        drive, strerror ( rc ) );
00339                 goto err_register;
00340         }
00341 
00342         /* Update media descriptor */
00343         block->media.BlockSize =
00344                 ( sandev->capacity.blksize << sandev->blksize_shift );
00345         block->media.LastBlock =
00346                 ( ( sandev->capacity.blocks >> sandev->blksize_shift ) - 1 );
00347 
00348         /* Install protocols */
00349         if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
00350                         &block->handle,
00351                         &efi_block_io_protocol_guid, &block->block_io,
00352                         &efi_device_path_protocol_guid, block->path,
00353                         NULL ) ) != 0 ) {
00354                 rc = -EEFI ( efirc );
00355                 DBGC ( sandev, "EFIBLK %#02x could not install protocols: %s\n",
00356                        sandev->drive, strerror ( rc ) );
00357                 goto err_install;
00358         }
00359 
00360         /* Connect all possible protocols */
00361         efi_block_connect ( sandev );
00362 
00363         return drive;
00364 
00365         bs->UninstallMultipleProtocolInterfaces (
00366                         block->handle,
00367                         &efi_block_io_protocol_guid, &block->block_io,
00368                         &efi_device_path_protocol_guid, block->path, NULL );
00369  err_install:
00370         unregister_sandev ( sandev );
00371  err_register:
00372         sandev_put ( sandev );
00373  err_alloc:
00374  err_no_snpdev:
00375  err_no_uris:
00376         return rc;
00377 }
00378 
00379 /**
00380  * Unhook EFI block device
00381  *
00382  * @v drive             Drive number
00383  */
00384 static void efi_block_unhook ( unsigned int drive ) {
00385         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00386         struct san_device *sandev;
00387         struct efi_block_data *block;
00388 
00389         /* Find SAN device */
00390         sandev = sandev_find ( drive );
00391         if ( ! sandev ) {
00392                 DBG ( "EFIBLK cannot find drive %#02x\n", drive );
00393                 return;
00394         }
00395         block = sandev->priv;
00396 
00397         /* Uninstall protocols */
00398         bs->UninstallMultipleProtocolInterfaces (
00399                         block->handle,
00400                         &efi_block_io_protocol_guid, &block->block_io,
00401                         &efi_device_path_protocol_guid, block->path, NULL );
00402 
00403         /* Unregister SAN device */
00404         unregister_sandev ( sandev );
00405 
00406         /* Drop reference to drive */
00407         sandev_put ( sandev );
00408 }
00409 
00410 /** An installed ACPI table */
00411 struct efi_acpi_table {
00412         /** List of installed tables */
00413         struct list_head list;
00414         /** Table key */
00415         UINTN key;
00416 };
00417 
00418 /** List of installed ACPI tables */
00419 static LIST_HEAD ( efi_acpi_tables );
00420 
00421 /**
00422  * Install ACPI table
00423  *
00424  * @v hdr               ACPI description header
00425  * @ret rc              Return status code
00426  */
00427 static int efi_block_install ( struct acpi_header *hdr ) {
00428         size_t len = le32_to_cpu ( hdr->length );
00429         struct efi_acpi_table *installed;
00430         EFI_STATUS efirc;
00431         int rc;
00432 
00433         /* Allocate installed table record */
00434         installed = zalloc ( sizeof ( *installed ) );
00435         if ( ! installed ) {
00436                 rc = -ENOMEM;
00437                 goto err_alloc;
00438         }
00439 
00440         /* Fill in common parameters */
00441         strncpy ( hdr->oem_id, "FENSYS", sizeof ( hdr->oem_id ) );
00442         strncpy ( hdr->oem_table_id, "iPXE", sizeof ( hdr->oem_table_id ) );
00443 
00444         /* Fix up ACPI checksum */
00445         acpi_fix_checksum ( hdr );
00446 
00447         /* Install table */
00448         if ( ( efirc = acpi->InstallAcpiTable ( acpi, hdr, len,
00449                                                 &installed->key ) ) != 0 ){
00450                 rc = -EEFI ( efirc );
00451                 DBGC ( acpi, "EFIBLK could not install %s: %s\n",
00452                        acpi_name ( hdr->signature ), strerror ( rc ) );
00453                 DBGC_HDA ( acpi, 0, hdr, len );
00454                 goto err_install;
00455         }
00456 
00457         /* Add to list of installed tables */
00458         list_add_tail ( &installed->list, &efi_acpi_tables );
00459 
00460         DBGC ( acpi, "EFIBLK installed %s as ACPI table %#lx:\n",
00461                acpi_name ( hdr->signature ),
00462                ( ( unsigned long ) installed->key ) );
00463         DBGC_HDA ( acpi, 0, hdr, len );
00464         return 0;
00465 
00466         list_del ( &installed->list );
00467  err_install:
00468         free ( installed );
00469  err_alloc:
00470         return rc;
00471 }
00472 
00473 /**
00474  * Describe EFI block devices
00475  *
00476  * @ret rc              Return status code
00477  */
00478 static int efi_block_describe ( void ) {
00479         struct efi_acpi_table *installed;
00480         struct efi_acpi_table *tmp;
00481         UINTN key;
00482         EFI_STATUS efirc;
00483         int rc;
00484 
00485         /* Sanity check */
00486         if ( ! acpi ) {
00487                 DBG ( "EFIBLK has no ACPI table protocol\n" );
00488                 return -ENOTSUP;
00489         }
00490 
00491         /* Uninstall any existing ACPI tables */
00492         list_for_each_entry_safe ( installed, tmp, &efi_acpi_tables, list ) {
00493                 key = installed->key;
00494                 if ( ( efirc = acpi->UninstallAcpiTable ( acpi, key ) ) != 0 ) {
00495                         rc = -EEFI ( efirc );
00496                         DBGC ( acpi, "EFIBLK could not uninstall ACPI table "
00497                                "%#lx: %s\n", ( ( unsigned long ) key ),
00498                                strerror ( rc ) );
00499                         /* Continue anyway */
00500                 }
00501                 list_del ( &installed->list );
00502                 free ( installed );
00503         }
00504 
00505         /* Install ACPI tables */
00506         if ( ( rc = acpi_install ( efi_block_install ) ) != 0 )  {
00507                 DBGC ( acpi, "EFIBLK could not install ACPI tables: %s\n",
00508                        strerror ( rc ) );
00509                 return rc;
00510         }
00511 
00512         return 0;
00513 }
00514 
00515 /**
00516  * Try booting from child device of EFI block device
00517  *
00518  * @v sandev            SAN device
00519  * @v handle            EFI handle
00520  * @v filename          Filename (or NULL to use default)
00521  * @v image             Image handle to fill in
00522  * @ret rc              Return status code
00523  */
00524 static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle,
00525                                   const char *filename, EFI_HANDLE *image ) {
00526         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00527         struct efi_block_data *block = sandev->priv;
00528         union {
00529                 EFI_DEVICE_PATH_PROTOCOL *path;
00530                 void *interface;
00531         } path;
00532         EFI_DEVICE_PATH_PROTOCOL *boot_path;
00533         FILEPATH_DEVICE_PATH *filepath;
00534         EFI_DEVICE_PATH_PROTOCOL *end;
00535         size_t prefix_len;
00536         size_t filepath_len;
00537         size_t boot_path_len;
00538         EFI_STATUS efirc;
00539         int rc;
00540 
00541         /* Identify device path */
00542         if ( ( efirc = bs->OpenProtocol ( handle,
00543                                           &efi_device_path_protocol_guid,
00544                                           &path.interface, efi_image_handle,
00545                                           handle,
00546                                           EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
00547                 DBGC ( sandev, "EFIBLK %#02x found filesystem with no device "
00548                        "path??", sandev->drive );
00549                 rc = -EEFI ( efirc );
00550                 goto err_open_device_path;
00551         }
00552 
00553         /* Check if this device is a child of our block device */
00554         prefix_len = efi_devpath_len ( block->path );
00555         if ( memcmp ( path.path, block->path, prefix_len ) != 0 ) {
00556                 /* Not a child device */
00557                 rc = -ENOTTY;
00558                 goto err_not_child;
00559         }
00560         DBGC ( sandev, "EFIBLK %#02x found child device %s\n",
00561                sandev->drive, efi_devpath_text ( path.path ) );
00562 
00563         /* Construct device path for boot image */
00564         end = efi_devpath_end ( path.path );
00565         prefix_len = ( ( ( void * ) end ) - ( ( void * ) path.path ) );
00566         filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH +
00567                          ( filename ?
00568                            ( ( strlen ( filename ) + 1 /* NUL */ ) *
00569                              sizeof ( filepath->PathName[0] ) ) :
00570                            sizeof ( efi_block_boot_filename ) ) );
00571         boot_path_len = ( prefix_len + filepath_len + sizeof ( *end ) );
00572         boot_path = zalloc ( boot_path_len );
00573         if ( ! boot_path ) {
00574                 rc = -ENOMEM;
00575                 goto err_alloc_path;
00576         }
00577         memcpy ( boot_path, path.path, prefix_len );
00578         filepath = ( ( ( void * ) boot_path ) + prefix_len );
00579         filepath->Header.Type = MEDIA_DEVICE_PATH;
00580         filepath->Header.SubType = MEDIA_FILEPATH_DP;
00581         filepath->Header.Length[0] = ( filepath_len & 0xff );
00582         filepath->Header.Length[1] = ( filepath_len >> 8 );
00583         if ( filename ) {
00584                 efi_sprintf ( filepath->PathName, "%s", filename );
00585         } else {
00586                 memcpy ( filepath->PathName, efi_block_boot_filename,
00587                          sizeof ( efi_block_boot_filename ) );
00588         }
00589         end = ( ( ( void * ) filepath ) + filepath_len );
00590         end->Type = END_DEVICE_PATH_TYPE;
00591         end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
00592         end->Length[0] = sizeof ( *end );
00593         DBGC ( sandev, "EFIBLK %#02x trying to load %s\n",
00594                sandev->drive, efi_devpath_text ( boot_path ) );
00595 
00596         /* Try loading boot image from this device */
00597         if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, boot_path,
00598                                        NULL, 0, image ) ) != 0 ) {
00599                 rc = -EEFI ( efirc );
00600                 DBGC ( sandev, "EFIBLK %#02x could not load image: %s\n",
00601                        sandev->drive, strerror ( rc ) );
00602                 goto err_load_image;
00603         }
00604 
00605         /* Success */
00606         rc = 0;
00607 
00608  err_load_image:
00609         free ( boot_path );
00610  err_alloc_path:
00611  err_not_child:
00612  err_open_device_path:
00613         return rc;
00614 }
00615 
00616 /**
00617  * Boot from EFI block device
00618  *
00619  * @v drive             Drive number
00620  * @v filename          Filename (or NULL to use default)
00621  * @ret rc              Return status code
00622  */
00623 static int efi_block_boot ( unsigned int drive, const char *filename ) {
00624         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00625         struct san_device *sandev;
00626         EFI_HANDLE *handles;
00627         EFI_HANDLE image = NULL;
00628         UINTN count;
00629         unsigned int i;
00630         EFI_STATUS efirc;
00631         int rc;
00632 
00633         /* Find SAN device */
00634         sandev = sandev_find ( drive );
00635         if ( ! sandev ) {
00636                 DBG ( "EFIBLK cannot find drive %#02x\n", drive );
00637                 rc = -ENODEV;
00638                 goto err_sandev_find;
00639         }
00640 
00641         /* Release SNP devices */
00642         efi_snp_release();
00643 
00644         /* Connect all possible protocols */
00645         efi_block_connect ( sandev );
00646 
00647         /* Locate all handles supporting the Simple File System protocol */
00648         if ( ( efirc = bs->LocateHandleBuffer (
00649                         ByProtocol, &efi_simple_file_system_protocol_guid,
00650                         NULL, &count, &handles ) ) != 0 ) {
00651                 rc = -EEFI ( efirc );
00652                 DBGC ( sandev, "EFIBLK %#02x cannot locate file systems: %s\n",
00653                        sandev->drive, strerror ( rc ) );
00654                 goto err_locate_file_systems;
00655         }
00656 
00657         /* Try booting from any available child device containing a
00658          * suitable boot image.  This is something of a wild stab in
00659          * the dark, but should end up conforming to user expectations
00660          * most of the time.
00661          */
00662         rc = -ENOENT;
00663         for ( i = 0 ; i < count ; i++ ) {
00664                 if ( ( rc = efi_block_boot_image ( sandev, handles[i], filename,
00665                                                    &image ) ) != 0 )
00666                         continue;
00667                 DBGC ( sandev, "EFIBLK %#02x found boot image\n",
00668                        sandev->drive );
00669                 efirc = bs->StartImage ( image, NULL, NULL );
00670                 rc = ( efirc ? -EEFI ( efirc ) : 0 );
00671                 bs->UnloadImage ( image );
00672                 DBGC ( sandev, "EFIBLK %#02x boot image returned: %s\n",
00673                        sandev->drive, strerror ( rc ) );
00674                 break;
00675         }
00676 
00677         bs->FreePool ( handles );
00678  err_locate_file_systems:
00679         efi_snp_claim();
00680  err_sandev_find:
00681         return rc;
00682 }
00683 
00684 PROVIDE_SANBOOT ( efi, san_hook, efi_block_hook );
00685 PROVIDE_SANBOOT ( efi, san_unhook, efi_block_unhook );
00686 PROVIDE_SANBOOT ( efi, san_describe, efi_block_describe );
00687 PROVIDE_SANBOOT ( efi, san_boot, efi_block_boot );