iPXE
snponly.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014 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 #include <string.h>
00027 #include <errno.h>
00028 #include <ipxe/init.h>
00029 #include <ipxe/efi/efi.h>
00030 #include <ipxe/efi/efi_driver.h>
00031 #include <ipxe/efi/efi_utils.h>
00032 #include <ipxe/efi/Protocol/SimpleNetwork.h>
00033 #include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
00034 #include "snpnet.h"
00035 #include "nii.h"
00036 
00037 /** @file
00038  *
00039  * EFI chainloaded-device-only driver
00040  *
00041  */
00042 
00043 /** A chainloaded protocol */
00044 struct chained_protocol {
00045         /** Protocol GUID */
00046         EFI_GUID *protocol;
00047         /**
00048          * Protocol instance installed on the loaded image's device handle
00049          *
00050          * We match against the protocol instance (rather than simply
00051          * matching against the device handle itself) because some
00052          * systems load us via a child of the underlying device, with
00053          * a duplicate protocol installed on the child handle.
00054          */
00055         void *interface;
00056 };
00057 
00058 /** Chainloaded SNP protocol */
00059 static struct chained_protocol chained_snp = {
00060         .protocol = &efi_simple_network_protocol_guid,
00061 };
00062 
00063 /** Chainloaded NII protocol */
00064 static struct chained_protocol chained_nii = {
00065         .protocol = &efi_nii31_protocol_guid,
00066 };
00067 
00068 /**
00069  * Locate chainloaded protocol instance
00070  *
00071  * @v chained           Chainloaded protocol
00072  * @ret rc              Return status code
00073  */
00074 static int chained_locate ( struct chained_protocol *chained ) {
00075         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00076         EFI_HANDLE device = efi_loaded_image->DeviceHandle;
00077         EFI_HANDLE parent;
00078         EFI_STATUS efirc;
00079         int rc;
00080 
00081         /* Locate handle supporting this protocol */
00082         if ( ( rc = efi_locate_device ( device, chained->protocol,
00083                                         &parent ) ) != 0 ) {
00084                 DBGC ( device, "CHAINED %s does not support %s: %s\n",
00085                        efi_handle_name ( device ),
00086                        efi_guid_ntoa ( chained->protocol ), strerror ( rc ) );
00087                 goto err_locate_device;
00088         }
00089         DBGC ( device, "CHAINED %s found %s on ", efi_handle_name ( device ),
00090                efi_guid_ntoa ( chained->protocol ) );
00091         DBGC ( device, "%s\n", efi_handle_name ( parent ) );
00092 
00093         /* Get protocol instance */
00094         if ( ( efirc = bs->OpenProtocol ( parent, chained->protocol,
00095                                           &chained->interface, efi_image_handle,
00096                                           device,
00097                                           EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
00098                 rc = -EEFI ( efirc );
00099                 DBGC ( device, "CHAINED %s could not open %s on ",
00100                        efi_handle_name ( device ),
00101                        efi_guid_ntoa ( chained->protocol ) );
00102                 DBGC ( device, "%s: %s\n",
00103                        efi_handle_name ( parent ), strerror ( rc ) );
00104                 goto err_open_protocol;
00105         }
00106 
00107  err_locate_device:
00108         bs->CloseProtocol ( parent, chained->protocol, efi_image_handle,
00109                             device );
00110  err_open_protocol:
00111         return rc;
00112 }
00113 
00114 /**
00115  * Check to see if driver supports a device
00116  *
00117  * @v device            EFI device handle
00118  * @v chained           Chainloaded protocol
00119  * @ret rc              Return status code
00120  */
00121 static int chained_supported ( EFI_HANDLE device,
00122                                struct chained_protocol *chained ) {
00123         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00124         EFI_STATUS efirc;
00125         void *interface;
00126         int rc;
00127 
00128         /* Get protocol */
00129         if ( ( efirc = bs->OpenProtocol ( device, chained->protocol, &interface,
00130                                           efi_image_handle, device,
00131                                           EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
00132                 rc = -EEFI ( efirc );
00133                 DBGCP ( device, "CHAINED %s is not a %s device\n",
00134                         efi_handle_name ( device ),
00135                         efi_guid_ntoa ( chained->protocol ) );
00136                 goto err_open_protocol;
00137         }
00138 
00139         /* Test for a match against the chainloading device */
00140         if ( interface != chained->interface ) {
00141                 DBGC ( device, "CHAINED %s %p is not the chainloaded %s\n",
00142                        efi_handle_name ( device ), interface,
00143                        efi_guid_ntoa ( chained->protocol ) );
00144                 rc = -ENOTTY;
00145                 goto err_no_match;
00146         }
00147 
00148         /* Success */
00149         rc = 0;
00150         DBGC ( device, "CHAINED %s %p is the chainloaded %s\n",
00151                efi_handle_name ( device ), interface,
00152                efi_guid_ntoa ( chained->protocol ) );
00153 
00154  err_no_match:
00155         bs->CloseProtocol ( device, chained->protocol, efi_image_handle,
00156                             device );
00157  err_open_protocol:
00158         return rc;
00159 }
00160 
00161 /**
00162  * Check to see if driver supports a device
00163  *
00164  * @v device            EFI device handle
00165  * @ret rc              Return status code
00166  */
00167 static int snponly_supported ( EFI_HANDLE device ) {
00168 
00169         return chained_supported ( device, &chained_snp );
00170 }
00171 
00172 /**
00173  * Check to see if driver supports a device
00174  *
00175  * @v device            EFI device handle
00176  * @ret rc              Return status code
00177  */
00178 static int niionly_supported ( EFI_HANDLE device ) {
00179 
00180         return chained_supported ( device, &chained_nii );
00181 }
00182 
00183 /** EFI SNP chainloading-device-only driver */
00184 struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
00185         .name = "SNPONLY",
00186         .supported = snponly_supported,
00187         .start = snpnet_start,
00188         .stop = snpnet_stop,
00189 };
00190 
00191 /** EFI NII chainloading-device-only driver */
00192 struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
00193         .name = "NIIONLY",
00194         .supported = niionly_supported,
00195         .start = nii_start,
00196         .stop = nii_stop,
00197 };
00198 
00199 /**
00200  * Initialise EFI chainloaded-device-only driver
00201  *
00202  */
00203 static void chained_init ( void ) {
00204 
00205         chained_locate ( &chained_snp );
00206         chained_locate ( &chained_nii );
00207 }
00208 
00209 /** EFI chainloaded-device-only initialisation function */
00210 struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = {
00211         .initialise = chained_init,
00212 };