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 FILE_SECBOOT ( PERMITTED );
22 
23 #include <string.h>
24 #include <errno.h>
25 #include <endian.h>
26 #include <ipxe/init.h>
27 #include <ipxe/rotate.h>
28 #include <ipxe/efi/efi.h>
29 #include <ipxe/efi/efi_table.h>
30 #include <ipxe/efi/efi_driver.h>
31 #include <ipxe/efi/efi_path.h>
32 #include <ipxe/efi/efi_cmdline.h>
34 
35 /** Image handle passed to entry point */
37 
38 /** Loaded image protocol for this image */
40 
41 /** Device path for the loaded image's device handle */
43 
44 /** System table passed to entry point
45  *
46  * We construct the symbol name efi_systab via the PLATFORM macro.
47  * This ensures that the symbol is defined only in EFI builds, and so
48  * prevents EFI code from being incorrectly linked in to a non-EFI
49  * build.
50  */
51 EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab );
52 
53 /** Internal task priority level */
55 
56 /** External task priority level */
58 
59 /** EFI shutdown is in progress */
61 
62 /** Event used to signal shutdown */
64 
65 /** Stack cookie */
66 unsigned long __stack_chk_guard;
67 
68 /** Exit function
69  *
70  * Cached to minimise external dependencies when a stack check
71  * failure is triggered.
72  */
74 
75 /* Forward declarations */
76 static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
77 
78 /**
79  * Shut down in preparation for booting an OS.
80  *
81  * This hook gets called at ExitBootServices time in order to make
82  * sure that everything is properly shut down before the OS takes
83  * over.
84  */
86  void *context __unused ) {
87 
88  /* This callback is invoked at TPL_NOTIFY in order to ensure
89  * that we have an opportunity to shut down cleanly before
90  * other shutdown hooks perform destructive operations such as
91  * disabling the IOMMU.
92  *
93  * Modify the internal task priority level so that no code
94  * attempts to raise from TPL_NOTIFY to TPL_CALLBACK (which
95  * would trigger a fatal exception).
96  */
98 
99  /* Mark shutdown as being in progress, to indicate that large
100  * parts of the system (e.g. timers) are no longer functional.
101  */
103 
104  /* Shut down iPXE */
105  shutdown_boot();
106 }
107 
108 /**
109  * Construct a stack cookie value
110  *
111  * @v handle Image handle
112  * @ret cookie Stack cookie
113  */
114 __attribute__ (( noinline )) unsigned long
116  unsigned long cookie = 0;
117  unsigned int rotation = ( 8 * sizeof ( cookie ) / 4 );
118 
119  /* There is no viable source of entropy available at this
120  * point. Construct a value that is at least likely to vary
121  * between platforms and invocations.
122  */
123  cookie ^= ( ( unsigned long ) handle );
124  cookie = roll ( cookie, rotation );
125  cookie ^= ( ( unsigned long ) &handle );
126  cookie = roll ( cookie, rotation );
127  cookie ^= profile_timestamp();
128  cookie = roll ( cookie, rotation );
129  cookie ^= build_id;
130 
131  /* Ensure that the value contains a NUL byte, to act as a
132  * runaway string terminator. Construct the NUL using a shift
133  * rather than a mask, to avoid losing valuable entropy in the
134  * lower-order bits.
135  */
136  cookie <<= 8;
137 
138  /* Ensure that the NUL byte is placed at the bottom of the
139  * stack cookie, to avoid potential disclosure via an
140  * unterminated string.
141  */
142  if ( __BYTE_ORDER == __BIG_ENDIAN )
143  cookie >>= 8;
144 
145  return cookie;
146 }
147 
148 /**
149  * Initialise EFI environment
150  *
151  * @v image_handle Image handle
152  * @v systab System table
153  * @ret efirc EFI return status code
154  */
156  EFI_SYSTEM_TABLE *systab ) {
157  EFI_BOOT_SERVICES *bs;
158  struct efi_protocol *prot;
159  struct efi_config_table *tab;
161  void *device_path_copy;
162  size_t device_path_len;
163  EFI_STATUS efirc;
164  int rc;
165 
166  /* Store image handle and system table pointer for future use */
167  efi_image_handle = image_handle;
168  efi_systab = systab;
169 
170  /* Sanity checks */
171  if ( ! systab ) {
172  efirc = EFI_NOT_AVAILABLE_YET;
173  goto err_sanity;
174  }
175  if ( ! systab->ConOut ) {
176  efirc = EFI_NOT_AVAILABLE_YET;
177  goto err_sanity;
178  }
179  if ( ! systab->BootServices ) {
180  DBGC ( systab, "EFI provided no BootServices entry point\n" );
181  efirc = EFI_NOT_AVAILABLE_YET;
182  goto err_sanity;
183  }
184  if ( ! systab->RuntimeServices ) {
185  DBGC ( systab, "EFI provided no RuntimeServices entry "
186  "point\n" );
187  efirc = EFI_NOT_AVAILABLE_YET;
188  goto err_sanity;
189  }
190  DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
191  bs = systab->BootServices;
192 
193  /* Store abort function pointer */
194  efi_exit = bs->Exit;
195 
196  /* Look up used protocols */
198  if ( ( efirc = bs->LocateProtocol ( &prot->guid, NULL,
199  prot->protocol ) ) == 0 ) {
200  DBGC ( systab, "EFI protocol %s is at %p\n",
201  efi_guid_ntoa ( &prot->guid ),
202  *(prot->protocol) );
203  } else {
204  DBGC ( systab, "EFI does not provide protocol %s\n",
205  efi_guid_ntoa ( &prot->guid ) );
206  /* Fail if protocol is required */
207  if ( prot->required )
208  goto err_missing_protocol;
209  }
210  }
211 
212  /* Look up used configuration tables */
214  if ( ( *(tab->table) = efi_find_table ( &tab->guid ) ) ) {
215  DBGC ( systab, "EFI configuration table %s is at %p\n",
216  efi_guid_ntoa ( &tab->guid ), *(tab->table) );
217  } else {
218  DBGC ( systab, "EFI does not provide configuration "
219  "table %s\n", efi_guid_ntoa ( &tab->guid ) );
220  if ( tab->required ) {
221  efirc = EFI_NOT_AVAILABLE_YET;
222  goto err_missing_table;
223  }
224  }
225  }
226 
227  /* Get loaded image protocol
228  *
229  * We assume that our loaded image protocol will not be
230  * uninstalled while our image code is still running.
231  */
232  if ( ( rc = efi_open_unsafe ( image_handle,
234  &efi_loaded_image ) ) != 0 ) {
235  DBGC ( systab, "EFI could not get loaded image protocol: %s",
236  strerror ( rc ) );
237  efirc = EFIRC ( rc );
238  goto err_no_loaded_image;
239  }
240  DBGC ( systab, "EFI image base address %p\n",
242 
243  /* Record command line */
246 
247  /* Get loaded image's device handle's device path */
250  &device_path ) ) != 0 ) {
251  DBGC ( systab, "EFI could not get loaded image's device path: "
252  "%s", strerror ( rc ) );
253  efirc = EFIRC ( rc );
254  goto err_no_device_path;
255  }
256 
257  /* Make a copy of the loaded image's device handle's device
258  * path, since the device handle itself may become invalidated
259  * when we load our own drivers.
260  */
261  device_path_len = ( efi_path_len ( device_path ) +
262  sizeof ( EFI_DEVICE_PATH_PROTOCOL ) );
263  if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, device_path_len,
264  &device_path_copy ) ) != 0 ) {
265  rc = -EEFI ( efirc );
266  goto err_alloc_device_path;
267  }
268  memcpy ( device_path_copy, device_path, device_path_len );
269  efi_loaded_image_path = device_path_copy;
270  DBGC ( systab, "EFI image device path %s\n",
272 
273  /* EFI is perfectly capable of gracefully shutting down any
274  * loaded devices if it decides to fall back to a legacy boot.
275  * For no particularly comprehensible reason, it doesn't
276  * bother doing so when ExitBootServices() is called.
277  */
278  if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
280  NULL, &efi_shutdown_event ) ) != 0 ) {
281  rc = -EEFI ( efirc );
282  DBGC ( systab, "EFI could not create ExitBootServices event: "
283  "%s\n", strerror ( rc ) );
284  goto err_create_event;
285  }
286 
287  /* Install driver binding protocol */
288  if ( ( rc = efi_driver_install() ) != 0 ) {
289  DBGC ( systab, "EFI could not install driver: %s\n",
290  strerror ( rc ) );
291  efirc = EFIRC ( rc );
292  goto err_driver_install;
293  }
294 
295  /* Install image unload method */
297 
298  return 0;
299 
301  err_driver_install:
303  err_create_event:
305  err_alloc_device_path:
306  err_no_device_path:
307  err_no_loaded_image:
308  err_missing_table:
309  err_missing_protocol:
310  err_sanity:
311  return efirc;
312 }
313 
314 /**
315  * Shut down EFI environment
316  *
317  * @v image_handle Image handle
318  */
319 static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
321  EFI_SYSTEM_TABLE *systab = efi_systab;
322  struct efi_saved_tpl tpl;
323 
324  DBGC ( systab, "EFI image unloading\n" );
325 
326  /* Raise TPL */
327  efi_raise_tpl ( &tpl );
328 
329  /* Shut down */
330  shutdown_exit();
331 
332  /* Disconnect any remaining devices */
334 
335  /* Uninstall driver binding protocol */
337 
338  /* Uninstall exit boot services event */
340 
341  /* Free copy of loaded image's device handle's device path */
343 
344  DBGC ( systab, "EFI image unloaded\n" );
345 
346  /* Restore TPL */
347  efi_restore_tpl ( &tpl );
348 
349  return 0;
350 }
351 
352 /**
353  * Abort on stack check failure
354  *
355  */
356 __attribute__ (( noreturn )) void __stack_chk_fail ( void ) {
357  EFI_STATUS efirc;
358  int rc;
359 
360  /* Report failure (when debugging) */
361  DBGC ( efi_systab, "EFI stack check failed (cookie %#lx); aborting\n",
363 
364  /* Attempt to exit cleanly with an error status */
365  if ( efi_exit ) {
367  0, NULL );
368  rc = -EEFI ( efirc );
369  DBGC ( efi_systab, "EFI stack check exit failed: %s\n",
370  strerror ( rc ) );
371  }
372 
373  /* If the exit fails for any reason, lock the system */
374  while ( 1 ) {}
375 
376 }
377 
378 /**
379  * Raise task priority level to internal level
380  *
381  * @v tpl Saved TPL
382  */
383 void efi_raise_tpl ( struct efi_saved_tpl *tpl ) {
385 
386  /* Record current external TPL */
387  tpl->previous = efi_external_tpl;
388 
389  /* Raise TPL and record previous TPL as new external TPL */
390  tpl->current = bs->RaiseTPL ( efi_internal_tpl );
391  efi_external_tpl = tpl->current;
392 }
393 
394 /**
395  * Restore task priority level
396  *
397  * @v tpl Saved TPL
398  */
399 void efi_restore_tpl ( struct efi_saved_tpl *tpl ) {
401 
402  /* Restore external TPL */
403  efi_external_tpl = tpl->previous;
404 
405  /* Restore TPL */
406  bs->RestoreTPL ( tpl->current );
407 }
void efi_driver_uninstall(void)
Uninstall EFI driver.
Definition: efi_driver.c:421
union edd_device_path device_path
Device path.
Definition: edd.h:25
#define __attribute__(x)
Definition: compiler.h:10
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
void ** protocol
Variable containing pointer to protocol structure.
Definition: efi.h:92
EFI_LOADED_IMAGE_PROTOCOL * efi_loaded_image
Loaded image protocol for this image.
Definition: efi_init.c:39
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:175
EFI_RAISE_TPL RaiseTPL
Definition: UefiSpec.h:1940
EFI driver interface.
const wchar_t * efi_cmdline
EFI command line (may not be wNUL-terminated.
Definition: efi_cmdline.c:46
EFI_LOCATE_PROTOCOL LocateProtocol
Definition: UefiSpec.h:2009
Error codes.
Definition: efi.h:63
void efi_raise_tpl(struct efi_saved_tpl *tpl)
Raise task priority level to internal level.
Definition: efi_init.c:383
#define TPL_APPLICATION
Definition: UefiSpec.h:648
#define efi_open_unsafe(handle, protocol, interface)
Open protocol for unsafe persistent use.
Definition: efi.h:459
EFI_GUID guid
GUID.
Definition: efi.h:90
#define __BYTE_ORDER
Definition: endian.h:7
#define DBGC(...)
Definition: compiler.h:505
EFI_GUID efi_loaded_image_protocol_guid
Loaded image protocol GUID.
Definition: efi_guid.c:273
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition: efi_path.c:174
EFI_CLOSE_EVENT CloseEvent
Definition: UefiSpec.h:1959
VOID * ImageBase
The base address at which the image was loaded.
Definition: LoadedImage.h:70
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition: DevicePath.h:46
EFI_TPL efi_internal_tpl
Internal task priority level.
Definition: efi_init.c:54
#define TPL_NOTIFY
Definition: UefiSpec.h:650
#define EFI_PROTOCOLS
EFI protocol table.
Definition: efi.h:98
FILE_LICENCE(GPL2_OR_LATER)
#define EVT_SIGNAL_EXIT_BOOT_SERVICES
Definition: UefiSpec.h:456
UEFI 2.0 Loaded image protocol definition.
#define EFI_CONFIG_TABLES
EFI configuration table table.
Definition: efi.h:142
An EFI configuration table used by iPXE.
Definition: efi.h:132
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:1006
FILE_SECBOOT(PERMITTED)
EFI_DEVICE_PATH_PROTOCOL * efi_loaded_image_path
Device path for the loaded image's device handle.
Definition: efi_init.c:42
void * memcpy(void *dest, const void *src, size_t len) __nonnull
EFI configuration tables.
#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:57
Can be used on any image handle to obtain information about the loaded image.
Definition: LoadedImage.h:46
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * ConOut
A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface that is associated with ConsoleOutHandle.
Definition: UefiSpec.h:2080
static EFI_EVENT efi_shutdown_event
Event used to signal shutdown.
Definition: efi_init.c:63
unsigned long build_id
Build ID.
Definition: version.c:62
EFI_TPL current
Current external TPL.
Definition: efi.h:82
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:85
#define EFI_COMPROMISED_DATA
Enumeration of EFI_STATUS.
Definition: UefiBaseType.h:146
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
EFI_CREATE_EVENT CreateEvent
Definition: UefiSpec.h:1955
static void shutdown_exit(void)
Shut down system for exit back to firmware.
Definition: init.h:86
const char * efi_devpath_text(EFI_DEVICE_PATH_PROTOCOL *path)
Get textual representation of device path.
Definition: efi_debug.c:247
VOID * LoadOptions
A pointer to the image's binary load options.
Definition: LoadedImage.h:65
#define __BIG_ENDIAN
Constant representing big-endian byte order.
Definition: endian.h:22
An EFI protocol used by iPXE.
Definition: efi.h:88
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
#define EFIAPI
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
EFI_IMAGE_UNLOAD Unload
Definition: LoadedImage.h:74
void efi_driver_disconnect_all(void)
Disconnect EFI driver from all possible devices.
Definition: efi_driver.c:648
EFI_TPL previous
Previous external TPL.
Definition: efi.h:84
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
#define TPL_CALLBACK
Definition: UefiSpec.h:649
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition: efi.h:444
EFI device paths.
EFI System Table.
Definition: UefiSpec.h:2044
unsigned long __stack_chk_guard
Stack cookie.
Definition: efi_init.c:66
static unsigned int rotation
Definition: rotate.h:23
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition: efi_guid.c:169
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition: efi_guid.c:726
EFI_FREE_POOL FreePool
Definition: UefiSpec.h:1950
EFI API.
void ** table
Variable containing pointer to configuration table.
Definition: efi.h:136
UINT32 LoadOptionsSize
The size in bytes of LoadOptions.
Definition: LoadedImage.h:64
int required
Protocol is required.
Definition: efi.h:94
EFI_RUNTIME_SERVICES * RuntimeServices
A pointer to the EFI Runtime Services Table.
Definition: UefiSpec.h:2095
UINTN EFI_TPL
Task priority level.
Definition: UefiBaseType.h:44
An EFI saved task priority level.
Definition: efi.h:80
EFI_GUID guid
GUID.
Definition: efi.h:134
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
EFI command line.
unsigned long profile_timestamp(void)
EFI_STATUS efi_init(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
Initialise EFI environment.
Definition: efi_init.c:155
static EFI_EXIT efi_exit
Exit function.
Definition: efi_init.c:73
EFI_SYSTEM_TABLE * efi_systab
EFI_SYSTEM_TABLE * _C2(PLATFORM, _systab)
System table passed to entry point.
size_t efi_cmdline_len
Length of EFI command line (in bytes)
Definition: efi_cmdline.c:49
EFI_RESTORE_TPL RestoreTPL
Definition: UefiSpec.h:1941
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:115
int required
Table is required for operation.
Definition: efi.h:138
static EFI_STATUS EFIAPI efi_unload(EFI_HANDLE image_handle)
Shut down EFI environment.
Definition: efi_init.c:319
void __stack_chk_fail(void)
Abort on stack check failure.
Definition: efi_init.c:356
static void shutdown_boot(void)
Shut down system for OS boot.
Definition: init.h:78
uint16_t handle
Handle.
Definition: smbios.h:17
void efi_restore_tpl(struct efi_saved_tpl *tpl)
Restore task priority level.
Definition: efi_init.c:399
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
void * efi_find_table(EFI_GUID *guid)
Look up EFI configuration table.
Definition: efi_table.c:45
int efi_driver_install(void)
Install EFI driver.
Definition: efi_driver.c:388
#define EFIRC(rc)
Convert an iPXE status code to an EFI status code.
Definition: efi.h:167
Definition: efi.h:62
EFI_HANDLE DeviceHandle
The device handle that the EFI Image was loaded from.
Definition: LoadedImage.h:56
EFI_ALLOCATE_POOL AllocatePool
Definition: UefiSpec.h:1949
Bit operations.
int efi_shutdown_in_progress
EFI shutdown is in progress.
Definition: efi_init.c:60
EFI_TPL efi_external_tpl
External task priority level.
Definition: efi_init.c:57