iPXE
efi_init.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19 
20 FILE_LICENCE ( GPL2_OR_LATER );
21 
22 #include <string.h>
23 #include <errno.h>
24 #include <endian.h>
25 #include <ipxe/init.h>
26 #include <ipxe/rotate.h>
27 #include <ipxe/efi/efi.h>
28 #include <ipxe/efi/efi_driver.h>
29 #include <ipxe/efi/efi_path.h>
31 
32 /** Image handle passed to entry point */
34 
35 /** Loaded image protocol for this image */
37 
38 /** Device path for the loaded image's device handle */
40 
41 /** System table passed to entry point
42  *
43  * We construct the symbol name efi_systab via the PLATFORM macro.
44  * This ensures that the symbol is defined only in EFI builds, and so
45  * prevents EFI code from being incorrectly linked in to a non-EFI
46  * build.
47  */
48 EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab );
49 
50 /** External task priority level */
52 
53 /** EFI shutdown is in progress */
55 
56 /** Event used to signal shutdown */
58 
59 /** Stack cookie */
60 unsigned long __stack_chk_guard;
61 
62 /** Exit function
63  *
64  * Cached to minimise external dependencies when a stack check
65  * failure is triggered.
66  */
68 
69 /* Forward declarations */
70 static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
71 
72 /**
73  * Shut down in preparation for booting an OS.
74  *
75  * This hook gets called at ExitBootServices time in order to make
76  * sure that everything is properly shut down before the OS takes
77  * over.
78  */
80  void *context __unused ) {
81 
82  /* Mark shutdown as being in progress, to indicate that large
83  * parts of the system (e.g. timers) are no longer functional.
84  */
86 
87  /* Shut down iPXE */
88  shutdown_boot();
89 }
90 
91 /**
92  * Look up EFI configuration table
93  *
94  * @v guid Configuration table GUID
95  * @ret table Configuration table, or NULL
96  */
97 static void * efi_find_table ( EFI_GUID *guid ) {
98  unsigned int i;
99 
100  for ( i = 0 ; i < efi_systab->NumberOfTableEntries ; i++ ) {
102  guid, sizeof ( *guid ) ) == 0 )
104  }
105 
106  return NULL;
107 }
108 
109 /**
110  * Construct a stack cookie value
111  *
112  * @v handle Image handle
113  * @ret cookie Stack cookie
114  */
115 __attribute__ (( noinline )) unsigned long
117  unsigned long cookie = 0;
118  unsigned int rotation = ( 8 * sizeof ( cookie ) / 4 );
119 
120  /* There is no viable source of entropy available at this
121  * point. Construct a value that is at least likely to vary
122  * between platforms and invocations.
123  */
124  cookie ^= ( ( unsigned long ) handle );
125  cookie = roll ( cookie, rotation );
126  cookie ^= ( ( unsigned long ) &handle );
127  cookie = roll ( cookie, rotation );
128  cookie ^= profile_timestamp();
129  cookie = roll ( cookie, rotation );
130  cookie ^= build_id;
131 
132  /* Ensure that the value contains a NUL byte, to act as a
133  * runaway string terminator. Construct the NUL using a shift
134  * rather than a mask, to avoid losing valuable entropy in the
135  * lower-order bits.
136  */
137  cookie <<= 8;
138 
139  /* Ensure that the NUL byte is placed at the bottom of the
140  * stack cookie, to avoid potential disclosure via an
141  * unterminated string.
142  */
143  if ( __BYTE_ORDER == __BIG_ENDIAN )
144  cookie >>= 8;
145 
146  return cookie;
147 }
148 
149 /**
150  * Initialise EFI environment
151  *
152  * @v image_handle Image handle
153  * @v systab System table
154  * @ret efirc EFI return status code
155  */
157  EFI_SYSTEM_TABLE *systab ) {
158  EFI_BOOT_SERVICES *bs;
159  struct efi_protocol *prot;
160  struct efi_config_table *tab;
161  void *loaded_image;
162  void *device_path;
163  void *device_path_copy;
164  size_t device_path_len;
165  EFI_STATUS efirc;
166  int rc;
167 
168  /* Store image handle and system table pointer for future use */
169  efi_image_handle = image_handle;
170  efi_systab = systab;
171 
172  /* Sanity checks */
173  if ( ! systab ) {
174  efirc = EFI_NOT_AVAILABLE_YET;
175  goto err_sanity;
176  }
177  if ( ! systab->ConOut ) {
178  efirc = EFI_NOT_AVAILABLE_YET;
179  goto err_sanity;
180  }
181  if ( ! systab->BootServices ) {
182  DBGC ( systab, "EFI provided no BootServices entry point\n" );
183  efirc = EFI_NOT_AVAILABLE_YET;
184  goto err_sanity;
185  }
186  if ( ! systab->RuntimeServices ) {
187  DBGC ( systab, "EFI provided no RuntimeServices entry "
188  "point\n" );
189  efirc = EFI_NOT_AVAILABLE_YET;
190  goto err_sanity;
191  }
192  DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
193  bs = systab->BootServices;
194 
195  /* Store abort function pointer */
196  efi_exit = bs->Exit;
197 
198  /* Look up used protocols */
200  if ( ( efirc = bs->LocateProtocol ( &prot->guid, NULL,
201  prot->protocol ) ) == 0 ) {
202  DBGC ( systab, "EFI protocol %s is at %p\n",
203  efi_guid_ntoa ( &prot->guid ),
204  *(prot->protocol) );
205  } else {
206  DBGC ( systab, "EFI does not provide protocol %s\n",
207  efi_guid_ntoa ( &prot->guid ) );
208  /* Fail if protocol is required */
209  if ( prot->required )
210  goto err_missing_protocol;
211  }
212  }
213 
214  /* Look up used configuration tables */
216  if ( ( *(tab->table) = efi_find_table ( &tab->guid ) ) ) {
217  DBGC ( systab, "EFI configuration table %s is at %p\n",
218  efi_guid_ntoa ( &tab->guid ), *(tab->table) );
219  } else {
220  DBGC ( systab, "EFI does not provide configuration "
221  "table %s\n", efi_guid_ntoa ( &tab->guid ) );
222  if ( tab->required ) {
223  efirc = EFI_NOT_AVAILABLE_YET;
224  goto err_missing_table;
225  }
226  }
227  }
228 
229  /* Get loaded image protocol */
230  if ( ( efirc = bs->OpenProtocol ( image_handle,
232  &loaded_image, image_handle, NULL,
233  EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
234  rc = -EEFI ( efirc );
235  DBGC ( systab, "EFI could not get loaded image protocol: %s",
236  strerror ( rc ) );
237  goto err_no_loaded_image;
238  }
239  efi_loaded_image = loaded_image;
240  DBGC ( systab, "EFI image base address %p\n",
242 
243  /* Get loaded image's device handle's device path */
244  if ( ( efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle,
246  &device_path, image_handle, NULL,
247  EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
248  rc = -EEFI ( efirc );
249  DBGC ( systab, "EFI could not get loaded image's device path: "
250  "%s", strerror ( rc ) );
251  goto err_no_device_path;
252  }
253 
254  /* Make a copy of the loaded image's device handle's device
255  * path, since the device handle itself may become invalidated
256  * when we load our own drivers.
257  */
258  device_path_len = ( efi_path_len ( device_path ) +
259  sizeof ( EFI_DEVICE_PATH_PROTOCOL ) );
260  if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, device_path_len,
261  &device_path_copy ) ) != 0 ) {
262  rc = -EEFI ( efirc );
263  goto err_alloc_device_path;
264  }
265  memcpy ( device_path_copy, device_path, device_path_len );
266  efi_loaded_image_path = device_path_copy;
267  DBGC ( systab, "EFI image device path %s\n",
269 
270  /* EFI is perfectly capable of gracefully shutting down any
271  * loaded devices if it decides to fall back to a legacy boot.
272  * For no particularly comprehensible reason, it doesn't
273  * bother doing so when ExitBootServices() is called.
274  */
275  if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
277  NULL, &efi_shutdown_event ) ) != 0 ) {
278  rc = -EEFI ( efirc );
279  DBGC ( systab, "EFI could not create ExitBootServices event: "
280  "%s\n", strerror ( rc ) );
281  goto err_create_event;
282  }
283 
284  /* Install driver binding protocol */
285  if ( ( rc = efi_driver_install() ) != 0 ) {
286  DBGC ( systab, "EFI could not install driver: %s\n",
287  strerror ( rc ) );
288  efirc = EFIRC ( rc );
289  goto err_driver_install;
290  }
291 
292  /* Install image unload method */
294 
295  return 0;
296 
298  err_driver_install:
300  err_create_event:
302  err_alloc_device_path:
303  err_no_device_path:
304  err_no_loaded_image:
305  err_missing_table:
306  err_missing_protocol:
307  err_sanity:
308  return efirc;
309 }
310 
311 /**
312  * Shut down EFI environment
313  *
314  * @v image_handle Image handle
315  */
316 static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
318  EFI_SYSTEM_TABLE *systab = efi_systab;
319 
320  DBGC ( systab, "EFI image unloading\n" );
321 
322  /* Shut down */
323  shutdown_exit();
324 
325  /* Disconnect any remaining devices */
327 
328  /* Uninstall driver binding protocol */
330 
331  /* Uninstall exit boot services event */
333 
334  /* Free copy of loaded image's device handle's device path */
336 
337  DBGC ( systab, "EFI image unloaded\n" );
338 
339  return 0;
340 }
341 
342 /**
343  * Abort on stack check failure
344  *
345  */
346 __attribute__ (( noreturn )) void __stack_chk_fail ( void ) {
347  EFI_STATUS efirc;
348  int rc;
349 
350  /* Report failure (when debugging) */
351  DBGC ( efi_systab, "EFI stack check failed (cookie %#lx); aborting\n",
353 
354  /* Attempt to exit cleanly with an error status */
355  if ( efi_exit ) {
357  0, NULL );
358  rc = -EEFI ( efirc );
359  DBGC ( efi_systab, "EFI stack check exit failed: %s\n",
360  strerror ( rc ) );
361  }
362 
363  /* If the exit fails for any reason, lock the system */
364  while ( 1 ) {}
365 
366 }
367 
368 /**
369  * Raise task priority level to TPL_CALLBACK
370  *
371  * @v tpl Saved TPL
372  */
373 void efi_raise_tpl ( struct efi_saved_tpl *tpl ) {
375 
376  /* Record current external TPL */
377  tpl->previous = efi_external_tpl;
378 
379  /* Raise TPL and record previous TPL as new external TPL */
380  tpl->current = bs->RaiseTPL ( TPL_CALLBACK );
381  efi_external_tpl = tpl->current;
382 }
383 
384 /**
385  * Restore task priority level
386  *
387  * @v tpl Saved TPL
388  */
389 void efi_restore_tpl ( struct efi_saved_tpl *tpl ) {
391 
392  /* Restore external TPL */
393  efi_external_tpl = tpl->previous;
394 
395  /* Restore TPL */
396  bs->RestoreTPL ( tpl->current );
397 }
void efi_driver_uninstall(void)
Uninstall EFI driver.
Definition: efi_driver.c:418
union edd_device_path device_path
Device path.
Definition: edd.h:24
#define __attribute__(x)
Definition: compiler.h:10
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2000
void ** protocol
Variable containing pointer to protocol structure.
Definition: efi.h:84
EFI_LOADED_IMAGE_PROTOCOL * efi_loaded_image
Loaded image protocol for this image.
Definition: efi_init.c:36
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:167
EFI_RAISE_TPL RaiseTPL
Definition: UefiSpec.h:1845
EFI driver interface.
EFI_LOCATE_PROTOCOL LocateProtocol
Definition: UefiSpec.h:1914
128 bit buffer containing a unique identifier value.
Definition: Base.h:263
Error codes.
void efi_raise_tpl(struct efi_saved_tpl *tpl)
Raise task priority level to TPL_CALLBACK.
Definition: efi_init.c:373
#define TPL_APPLICATION
Definition: UefiSpec.h:590
VOID * EFI_EVENT
Handle to an event structure.
Definition: UefiBaseType.h:43
EFI_GUID VendorGuid
The 128-bit GUID value that uniquely identifies the system configuration table.
Definition: UefiSpec.h:1939
EFI_GUID guid
GUID.
Definition: efi.h:82
#define __BYTE_ORDER
Definition: endian.h:6
#define DBGC(...)
Definition: compiler.h:505
EFI_GUID efi_loaded_image_protocol_guid
Loaded image protocol GUID.
Definition: efi_guid.c:184
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition: efi_path.c:67
EFI_CLOSE_EVENT CloseEvent
Definition: UefiSpec.h:1864
VOID * ImageBase
The base address at which the image was loaded.
Definition: LoadedImage.h:75
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition: DevicePath.h:51
#define EFI_PROTOCOLS
EFI protocol table.
Definition: efi.h:90
FILE_LICENCE(GPL2_OR_LATER)
#define EVT_SIGNAL_EXIT_BOOT_SERVICES
Definition: UefiSpec.h:396
UEFI 2.0 Loaded image protocol definition.
#define EFI_CONFIG_TABLES
EFI configuration table table.
Definition: efi.h:134
An EFI configuration table used by iPXE.
Definition: efi.h:124
EFI_STATUS(EFIAPI * EFI_EXIT)(IN EFI_HANDLE ImageHandle, IN EFI_STATUS ExitStatus, IN UINTN ExitDataSize, IN CHAR16 *ExitData OPTIONAL)
Terminates a loaded EFI image and returns control to boot services.
Definition: UefiSpec.h:925
EFI_DEVICE_PATH_PROTOCOL * efi_loaded_image_path
Device path for the loaded image's device handle.
Definition: efi_init.c:39
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define EFI_NOT_AVAILABLE_YET
If this value is returned by an API, it means the capability is not yet installed/available/ready to ...
Definition: PiMultiPhase.h:55
Can be used on any image handle to obtain information about the loaded image.
Definition: LoadedImage.h:51
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * ConOut
A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface that is associated with ConsoleOutHandle.
Definition: UefiSpec.h:1982
static EFI_EVENT efi_shutdown_event
Event used to signal shutdown.
Definition: efi_init.c:57
unsigned long build_id
Build ID.
Definition: version.c:60
EFI_TPL current
Current external TPL.
Definition: efi.h:74
static EFIAPI void efi_shutdown_hook(EFI_EVENT event __unused, void *context __unused)
Shut down in preparation for booting an OS.
Definition: efi_init.c:79
#define EFI_COMPROMISED_DATA
Enumeration of EFI_STATUS.
Definition: UefiBaseType.h:151
EFI_CREATE_EVENT CreateEvent
Definition: UefiSpec.h:1860
static void * efi_find_table(EFI_GUID *guid)
Look up EFI configuration table.
Definition: efi_init.c:97
static void shutdown_exit(void)
Shut down system for exit back to firmware.
Definition: init.h:84
const char * efi_devpath_text(EFI_DEVICE_PATH_PROTOCOL *path)
Get textual representation of device path.
Definition: efi_debug.c:366
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL
Definition: UefiSpec.h:1271
#define __BIG_ENDIAN
Constant representing big-endian byte order.
Definition: endian.h:18
An EFI protocol used by iPXE.
Definition: efi.h:80
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition: efi_debug.c:192
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
#define EFIAPI
EFI Boot Services Table.
Definition: UefiSpec.h:1836
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:33
EFI_IMAGE_UNLOAD Unload
Definition: LoadedImage.h:79
void efi_driver_disconnect_all(void)
Disconnect EFI driver from all possible devices.
Definition: efi_driver.c:584
EFI_TPL previous
Previous external TPL.
Definition: efi.h:76
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:358
#define TPL_CALLBACK
Definition: UefiSpec.h:591
EFI device paths.
EFI System Table.
Definition: UefiSpec.h:1949
unsigned long __stack_chk_guard
Stack cookie.
Definition: efi_init.c:60
static unsigned int rotation
Definition: rotate.h:22
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition: efi_guid.c:132
EFI_FREE_POOL FreePool
Definition: UefiSpec.h:1855
EFI API.
void ** table
Variable containing pointer to configuration table.
Definition: efi.h:128
uint64_t guid
GUID.
Definition: edd.h:30
int required
Protocol is required.
Definition: efi.h:86
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
EFI_RUNTIME_SERVICES * RuntimeServices
A pointer to the EFI Runtime Services Table.
Definition: UefiSpec.h:1996
UINTN EFI_TPL
Task priority level.
Definition: UefiBaseType.h:47
An EFI saved task priority level.
Definition: efi.h:72
EFI_GUID guid
GUID.
Definition: efi.h:126
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:35
UINTN NumberOfTableEntries
The number of system configuration tables in the buffer ConfigurationTable.
Definition: UefiSpec.h:2004
EFI_STATUS efi_init(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
Initialise EFI environment.
Definition: efi_init.c:156
static EFI_EXIT efi_exit
Exit function.
Definition: efi_init.c:67
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
Definition: UefiSpec.h:1905
EFI_SYSTEM_TABLE * _C2(PLATFORM, _systab)
System table passed to entry point.
EFI_RESTORE_TPL RestoreTPL
Definition: UefiSpec.h:1846
The data portions of a loaded Boot Serves Driver, and the default data allocation type used by a Boot...
unsigned long efi_stack_cookie(EFI_HANDLE handle)
Construct a stack cookie value.
Definition: efi_init.c:116
int required
Table is required for operation.
Definition: efi.h:130
static EFI_STATUS EFIAPI efi_unload(EFI_HANDLE image_handle)
Shut down EFI environment.
Definition: efi_init.c:316
void __stack_chk_fail(void)
Abort on stack check failure.
Definition: efi_init.c:346
static void shutdown_boot(void)
Shut down system for OS boot.
Definition: init.h:76
uint16_t handle
Handle.
Definition: smbios.h:16
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:113
void efi_restore_tpl(struct efi_saved_tpl *tpl)
Restore task priority level.
Definition: efi_init.c:389
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
String functions.
int efi_driver_install(void)
Install EFI driver.
Definition: efi_driver.c:385
#define EFIRC(rc)
Convert an iPXE status code to an EFI status code.
Definition: efi.h:159
Definition: efi.h:55
EFI_HANDLE DeviceHandle
The device handle that the EFI Image was loaded from.
Definition: LoadedImage.h:61
EFI_ALLOCATE_POOL AllocatePool
Definition: UefiSpec.h:1854
Bit operations.
EFI_CONFIGURATION_TABLE * ConfigurationTable
A pointer to the system configuration tables.
Definition: UefiSpec.h:2009
int efi_shutdown_in_progress
EFI shutdown is in progress.
Definition: efi_init.c:54
VOID * VendorTable
A pointer to the table associated with VendorGuid.
Definition: UefiSpec.h:1943
EFI_TPL efi_external_tpl
External task priority level.
Definition: efi_init.c:51