iPXE
efi_init.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 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 
00020 FILE_LICENCE ( GPL2_OR_LATER );
00021 
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <ipxe/init.h>
00025 #include <ipxe/efi/efi.h>
00026 #include <ipxe/efi/efi_driver.h>
00027 #include <ipxe/efi/Protocol/LoadedImage.h>
00028 
00029 /** Image handle passed to entry point */
00030 EFI_HANDLE efi_image_handle;
00031 
00032 /** Loaded image protocol for this image */
00033 EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
00034 
00035 /** System table passed to entry point
00036  *
00037  * We construct the symbol name efi_systab via the PLATFORM macro.
00038  * This ensures that the symbol is defined only in EFI builds, and so
00039  * prevents EFI code from being incorrectly linked in to a non-EFI
00040  * build.
00041  */
00042 EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab );
00043 
00044 /** EFI shutdown is in progress */
00045 int efi_shutdown_in_progress;
00046 
00047 /** Event used to signal shutdown */
00048 static EFI_EVENT efi_shutdown_event;
00049 
00050 /* Forward declarations */
00051 static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
00052 
00053 /**
00054  * Shut down in preparation for booting an OS.
00055  *
00056  * This hook gets called at ExitBootServices time in order to make
00057  * sure that everything is properly shut down before the OS takes
00058  * over.
00059  */
00060 static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
00061                                        void *context __unused ) {
00062 
00063         /* Mark shutdown as being in progress, to indicate that large
00064          * parts of the system (e.g. timers) are no longer functional.
00065          */
00066         efi_shutdown_in_progress = 1;
00067 
00068         /* Shut down iPXE */
00069         shutdown_boot();
00070 }
00071 
00072 /**
00073  * Look up EFI configuration table
00074  *
00075  * @v guid              Configuration table GUID
00076  * @ret table           Configuration table, or NULL
00077  */
00078 static void * efi_find_table ( EFI_GUID *guid ) {
00079         unsigned int i;
00080 
00081         for ( i = 0 ; i < efi_systab->NumberOfTableEntries ; i++ ) {
00082                 if ( memcmp ( &efi_systab->ConfigurationTable[i].VendorGuid,
00083                               guid, sizeof ( *guid ) ) == 0 )
00084                         return efi_systab->ConfigurationTable[i].VendorTable;
00085         }
00086 
00087         return NULL;
00088 }
00089 
00090 /**
00091  * Initialise EFI environment
00092  *
00093  * @v image_handle      Image handle
00094  * @v systab            System table
00095  * @ret efirc           EFI return status code
00096  */
00097 EFI_STATUS efi_init ( EFI_HANDLE image_handle,
00098                       EFI_SYSTEM_TABLE *systab ) {
00099         EFI_BOOT_SERVICES *bs;
00100         struct efi_protocol *prot;
00101         struct efi_config_table *tab;
00102         void *loaded_image;
00103         EFI_STATUS efirc;
00104         int rc;
00105 
00106         /* Store image handle and system table pointer for future use */
00107         efi_image_handle = image_handle;
00108         efi_systab = systab;
00109 
00110         /* Sanity checks */
00111         if ( ! systab ) {
00112                 efirc = EFI_NOT_AVAILABLE_YET;
00113                 goto err_sanity;
00114         }
00115         if ( ! systab->ConOut ) {
00116                 efirc = EFI_NOT_AVAILABLE_YET;
00117                 goto err_sanity;
00118         }
00119         if ( ! systab->BootServices ) {
00120                 DBGC ( systab, "EFI provided no BootServices entry point\n" );
00121                 efirc = EFI_NOT_AVAILABLE_YET;
00122                 goto err_sanity;
00123         }
00124         if ( ! systab->RuntimeServices ) {
00125                 DBGC ( systab, "EFI provided no RuntimeServices entry "
00126                        "point\n" );
00127                 efirc = EFI_NOT_AVAILABLE_YET;
00128                 goto err_sanity;
00129         }
00130         DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
00131         bs = systab->BootServices;
00132 
00133         /* Look up used protocols */
00134         for_each_table_entry ( prot, EFI_PROTOCOLS ) {
00135                 if ( ( efirc = bs->LocateProtocol ( &prot->guid, NULL,
00136                                                     prot->protocol ) ) == 0 ) {
00137                         DBGC ( systab, "EFI protocol %s is at %p\n",
00138                                efi_guid_ntoa ( &prot->guid ),
00139                                *(prot->protocol) );
00140                 } else {
00141                         DBGC ( systab, "EFI does not provide protocol %s\n",
00142                                efi_guid_ntoa ( &prot->guid ) );
00143                         /* Fail if protocol is required */
00144                         if ( prot->required )
00145                                 goto err_missing_protocol;
00146                 }
00147         }
00148 
00149         /* Look up used configuration tables */
00150         for_each_table_entry ( tab, EFI_CONFIG_TABLES ) {
00151                 if ( ( *(tab->table) = efi_find_table ( &tab->guid ) ) ) {
00152                         DBGC ( systab, "EFI configuration table %s is at %p\n",
00153                                efi_guid_ntoa ( &tab->guid ), *(tab->table) );
00154                 } else {
00155                         DBGC ( systab, "EFI does not provide configuration "
00156                                "table %s\n", efi_guid_ntoa ( &tab->guid ) );
00157                         if ( tab->required ) {
00158                                 efirc = EFI_NOT_AVAILABLE_YET;
00159                                 goto err_missing_table;
00160                         }
00161                 }
00162         }
00163 
00164         /* Get loaded image protocol */
00165         if ( ( efirc = bs->OpenProtocol ( image_handle,
00166                                 &efi_loaded_image_protocol_guid,
00167                                 &loaded_image, image_handle, NULL,
00168                                 EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
00169                 rc = -EEFI ( efirc );
00170                 DBGC ( systab, "EFI could not get loaded image protocol: %s",
00171                        strerror ( rc ) );
00172                 goto err_no_loaded_image;
00173         }
00174         efi_loaded_image = loaded_image;
00175         DBGC ( systab, "EFI image base address %p\n",
00176                efi_loaded_image->ImageBase );
00177 
00178         /* EFI is perfectly capable of gracefully shutting down any
00179          * loaded devices if it decides to fall back to a legacy boot.
00180          * For no particularly comprehensible reason, it doesn't
00181          * bother doing so when ExitBootServices() is called.
00182          */
00183         if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
00184                                          TPL_CALLBACK, efi_shutdown_hook,
00185                                          NULL, &efi_shutdown_event ) ) != 0 ) {
00186                 rc = -EEFI ( efirc );
00187                 DBGC ( systab, "EFI could not create ExitBootServices event: "
00188                        "%s\n", strerror ( rc ) );
00189                 goto err_create_event;
00190         }
00191 
00192         /* Install driver binding protocol */
00193         if ( ( rc = efi_driver_install() ) != 0 ) {
00194                 DBGC ( systab, "EFI could not install driver: %s\n",
00195                        strerror ( rc ) );
00196                 efirc = EFIRC ( rc );
00197                 goto err_driver_install;
00198         }
00199 
00200         /* Install image unload method */
00201         efi_loaded_image->Unload = efi_unload;
00202 
00203         return 0;
00204 
00205         efi_driver_uninstall();
00206  err_driver_install:
00207         bs->CloseEvent ( efi_shutdown_event );
00208  err_create_event:
00209  err_no_loaded_image:
00210  err_missing_table:
00211  err_missing_protocol:
00212  err_sanity:
00213         return efirc;
00214 }
00215 
00216 /**
00217  * Shut down EFI environment
00218  *
00219  * @v image_handle      Image handle
00220  */
00221 static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
00222         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00223         EFI_SYSTEM_TABLE *systab = efi_systab;
00224 
00225         DBGC ( systab, "EFI image unloading\n" );
00226 
00227         /* Shut down */
00228         shutdown_exit();
00229 
00230         /* Disconnect any remaining devices */
00231         efi_driver_disconnect_all();
00232 
00233         /* Uninstall driver binding protocol */
00234         efi_driver_uninstall();
00235 
00236         /* Uninstall exit boot services event */
00237         bs->CloseEvent ( efi_shutdown_event );
00238 
00239         DBGC ( systab, "EFI image unloaded\n" );
00240 
00241         return 0;
00242 }