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
20FILE_LICENCE ( GPL2_OR_LATER );
21FILE_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>
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 */
51EFI_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 */
66unsigned 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 */
76static 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 */
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 ) {
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",
241 efi_loaded_image->ImageBase );
242
243 /* Record command line */
244 efi_cmdline = efi_loaded_image->LoadOptions;
245 efi_cmdline_len = efi_loaded_image->LoadOptionsSize;
246
247 /* Get loaded image's device handle's device path */
248 if ( ( rc = efi_open ( efi_loaded_image->DeviceHandle,
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 */
320 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
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 */
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 */
383void efi_raise_tpl ( struct efi_saved_tpl *tpl ) {
384 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
385
386 /* Record current external TPL */
388
389 /* Raise TPL and record previous TPL as new external TPL */
390 tpl->current = bs->RaiseTPL ( efi_internal_tpl );
392}
393
394/**
395 * Restore task priority level
396 *
397 * @v tpl Saved TPL
398 */
399void efi_restore_tpl ( struct efi_saved_tpl *tpl ) {
400 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
401
402 /* Restore external TPL */
404
405 /* Restore TPL */
406 bs->RestoreTPL ( tpl->current );
407}
#define EFIAPI
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
UEFI 2.0 Loaded image protocol definition.
#define EFI_NOT_AVAILABLE_YET
If this value is returned by an API, it means the capability is not yet installed/available/ready to ...
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
#define EFI_COMPROMISED_DATA
Enumeration of EFI_STATUS.
UINTN EFI_TPL
Task priority level.
@ EfiBootServicesData
The data portions of a loaded Boot Serves Driver, and the default data allocation type used by a Boot...
#define TPL_CALLBACK
Definition UefiSpec.h:649
#define EVT_SIGNAL_EXIT_BOOT_SERVICES
Definition UefiSpec.h:456
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
#define TPL_APPLICATION
Definition UefiSpec.h:648
#define TPL_NOTIFY
Definition UefiSpec.h:650
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
#define __BYTE_ORDER
Definition endian.h:7
union edd_device_path device_path
Device path.
Definition edd.h:13
size_t efi_cmdline_len
Length of EFI command line (in bytes)
Definition efi_cmdline.c:49
const wchar_t * efi_cmdline
EFI command line (may not be wNUL-terminated.
Definition efi_cmdline.c:46
EFI command line.
const char * efi_devpath_text(EFI_DEVICE_PATH_PROTOCOL *path)
Get textual representation of device path.
Definition efi_debug.c:247
void efi_driver_disconnect_all(void)
Disconnect EFI driver from all possible devices.
Definition efi_driver.c:648
int efi_driver_install(void)
Install EFI driver.
Definition efi_driver.c:388
void efi_driver_uninstall(void)
Uninstall EFI driver.
Definition efi_driver.c:421
EFI driver interface.
EFI_GUID efi_loaded_image_protocol_guid
Loaded image protocol GUID.
Definition efi_guid.c:273
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition efi_guid.c:726
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition efi_guid.c:169
void __stack_chk_fail(void)
Abort on stack check failure.
Definition efi_init.c:356
EFI_STATUS efi_init(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
Initialise EFI environment.
Definition efi_init.c:155
EFI_TPL efi_external_tpl
External task priority level.
Definition efi_init.c:57
static EFI_EXIT efi_exit
Exit function.
Definition efi_init.c:73
EFI_TPL efi_internal_tpl
Internal task priority level.
Definition efi_init.c:54
EFI_DEVICE_PATH_PROTOCOL * efi_loaded_image_path
Device path for the loaded image's device handle.
Definition efi_init.c:42
static EFI_STATUS EFIAPI efi_unload(EFI_HANDLE image_handle)
Shut down EFI environment.
Definition efi_init.c:319
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
unsigned long __stack_chk_guard
Stack cookie.
Definition efi_init.c:66
unsigned long efi_stack_cookie(EFI_HANDLE handle)
Construct a stack cookie value.
Definition efi_init.c:115
EFI_LOADED_IMAGE_PROTOCOL * efi_loaded_image
Loaded image protocol for this image.
Definition efi_init.c:39
void efi_raise_tpl(struct efi_saved_tpl *tpl)
Raise task priority level to internal level.
Definition efi_init.c:383
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition efi_init.c:36
static EFI_EVENT efi_shutdown_event
Event used to signal shutdown.
Definition efi_init.c:63
int efi_shutdown_in_progress
EFI shutdown is in progress.
Definition efi_init.c:60
void efi_restore_tpl(struct efi_saved_tpl *tpl)
Restore task priority level.
Definition efi_init.c:399
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition efi_path.c:174
EFI device paths.
void * efi_find_table(EFI_GUID *guid)
Look up EFI configuration table.
Definition efi_table.c:45
EFI configuration tables.
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define __attribute__(x)
Definition compiler.h:10
#define _C2(x, y)
Concatenate expanded arguments.
Definition compiler.h:48
#define __BIG_ENDIAN
Constant representing big-endian byte order.
Definition endian.h:22
EFI API.
#define EFI_PROTOCOLS
EFI protocol table.
Definition efi.h:98
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition efi.h:444
#define EFIRC(rc)
Convert an iPXE status code to an EFI status code.
Definition efi.h:167
#define EFI_HANDLE
Definition efi.h:53
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition efi.h:175
#define efi_open_unsafe(handle, protocol, interface)
Open protocol for unsafe persistent use.
Definition efi.h:459
#define EFI_EVENT
Definition efi.h:54
#define EFI_CONFIG_TABLES
EFI configuration table table.
Definition efi.h:142
EFI_SYSTEM_TABLE * efi_systab
unsigned long profile_timestamp(void)
uint16_t handle
Handle.
Definition smbios.h:5
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static void shutdown_exit(void)
Shut down system for exit back to firmware.
Definition init.h:86
static void shutdown_boot(void)
Shut down system for OS boot.
Definition init.h:78
Bit operations.
static unsigned int rotation
Definition rotate.h:23
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
EFI Boot Services Table.
Definition UefiSpec.h:1931
EFI_RESTORE_TPL RestoreTPL
Definition UefiSpec.h:1941
EFI_FREE_POOL FreePool
Definition UefiSpec.h:1950
EFI_CREATE_EVENT CreateEvent
Definition UefiSpec.h:1955
EFI_LOCATE_PROTOCOL LocateProtocol
Definition UefiSpec.h:2009
EFI_CLOSE_EVENT CloseEvent
Definition UefiSpec.h:1959
EFI_ALLOCATE_POOL AllocatePool
Definition UefiSpec.h:1949
EFI_RAISE_TPL RaiseTPL
Definition UefiSpec.h:1940
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition DevicePath.h:46
Can be used on any image handle to obtain information about the loaded image.
Definition LoadedImage.h:46
EFI System Table.
Definition UefiSpec.h:2044
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition UefiSpec.h:2099
EFI_RUNTIME_SERVICES * RuntimeServices
A pointer to the EFI Runtime Services Table.
Definition UefiSpec.h:2095
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
An EFI configuration table used by iPXE.
Definition efi.h:132
int required
Table is required for operation.
Definition efi.h:138
void ** table
Variable containing pointer to configuration table.
Definition efi.h:136
EFI_GUID guid
GUID.
Definition efi.h:134
An EFI protocol used by iPXE.
Definition efi.h:88
EFI_GUID guid
GUID.
Definition efi.h:90
int required
Protocol is required.
Definition efi.h:94
void ** protocol
Variable containing pointer to protocol structure.
Definition efi.h:92
An EFI saved task priority level.
Definition efi.h:80
EFI_TPL previous
Previous external TPL.
Definition efi.h:84
EFI_TPL current
Current external TPL.
Definition efi.h:82
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
unsigned long build_id
Build ID.
Definition version.c:62