Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/efi/libstub/efi-stub-helper.c
26483 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Helper functions used by the EFI stub on multiple
4
* architectures. This should be #included by the EFI stub
5
* implementation files.
6
*
7
* Copyright 2011 Intel Corporation; author Matt Fleming
8
*/
9
10
#include <linux/stdarg.h>
11
12
#include <linux/efi.h>
13
#include <linux/kernel.h>
14
#include <linux/overflow.h>
15
#include <asm/efi.h>
16
#include <asm/setup.h>
17
18
#include "efistub.h"
19
20
bool efi_nochunk;
21
bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
22
bool efi_novamap;
23
24
static bool efi_noinitrd;
25
static bool efi_nosoftreserve;
26
static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
27
28
int efi_mem_encrypt;
29
30
bool __pure __efi_soft_reserve_enabled(void)
31
{
32
return !efi_nosoftreserve;
33
}
34
35
/**
36
* efi_parse_options() - Parse EFI command line options
37
* @cmdline: kernel command line
38
*
39
* Parse the ASCII string @cmdline for EFI options, denoted by the efi=
40
* option, e.g. efi=nochunk.
41
*
42
* It should be noted that efi= is parsed in two very different
43
* environments, first in the early boot environment of the EFI boot
44
* stub, and subsequently during the kernel boot.
45
*
46
* Return: status code
47
*/
48
efi_status_t efi_parse_options(char const *cmdline)
49
{
50
char *buf __free(efi_pool) = NULL;
51
efi_status_t status;
52
size_t len;
53
char *str;
54
55
if (!cmdline)
56
return EFI_SUCCESS;
57
58
len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1;
59
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
60
if (status != EFI_SUCCESS)
61
return status;
62
63
memcpy(buf, cmdline, len - 1);
64
buf[len - 1] = '\0';
65
str = skip_spaces(buf);
66
67
while (*str) {
68
char *param, *val;
69
70
str = next_arg(str, &param, &val);
71
if (!val && !strcmp(param, "--"))
72
break;
73
74
if (!strcmp(param, "nokaslr")) {
75
efi_nokaslr = true;
76
} else if (!strcmp(param, "quiet")) {
77
efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
78
} else if (!strcmp(param, "noinitrd")) {
79
efi_noinitrd = true;
80
} else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) {
81
efi_no5lvl = true;
82
} else if (IS_ENABLED(CONFIG_ARCH_HAS_MEM_ENCRYPT) &&
83
!strcmp(param, "mem_encrypt") && val) {
84
if (parse_option_str(val, "on"))
85
efi_mem_encrypt = 1;
86
else if (parse_option_str(val, "off"))
87
efi_mem_encrypt = -1;
88
} else if (!strcmp(param, "efi") && val) {
89
efi_nochunk = parse_option_str(val, "nochunk");
90
efi_novamap |= parse_option_str(val, "novamap");
91
92
efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
93
parse_option_str(val, "nosoftreserve");
94
95
if (parse_option_str(val, "disable_early_pci_dma"))
96
efi_disable_pci_dma = true;
97
if (parse_option_str(val, "no_disable_early_pci_dma"))
98
efi_disable_pci_dma = false;
99
if (parse_option_str(val, "debug"))
100
efi_loglevel = CONSOLE_LOGLEVEL_DEBUG;
101
} else if (!strcmp(param, "video") &&
102
val && strstarts(val, "efifb:")) {
103
efi_parse_option_graphics(val + strlen("efifb:"));
104
}
105
}
106
return EFI_SUCCESS;
107
}
108
109
/*
110
* The EFI_LOAD_OPTION descriptor has the following layout:
111
* u32 Attributes;
112
* u16 FilePathListLength;
113
* u16 Description[];
114
* efi_device_path_protocol_t FilePathList[];
115
* u8 OptionalData[];
116
*
117
* This function validates and unpacks the variable-size data fields.
118
*/
119
static
120
bool efi_load_option_unpack(efi_load_option_unpacked_t *dest,
121
const efi_load_option_t *src, size_t size)
122
{
123
const void *pos;
124
u16 c;
125
efi_device_path_protocol_t header;
126
const efi_char16_t *description;
127
const efi_device_path_protocol_t *file_path_list;
128
129
if (size < offsetof(efi_load_option_t, variable_data))
130
return false;
131
pos = src->variable_data;
132
size -= offsetof(efi_load_option_t, variable_data);
133
134
if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0)
135
return false;
136
137
/* Scan description. */
138
description = pos;
139
do {
140
if (size < sizeof(c))
141
return false;
142
c = *(const u16 *)pos;
143
pos += sizeof(c);
144
size -= sizeof(c);
145
} while (c != L'\0');
146
147
/* Scan file_path_list. */
148
file_path_list = pos;
149
do {
150
if (size < sizeof(header))
151
return false;
152
header = *(const efi_device_path_protocol_t *)pos;
153
if (header.length < sizeof(header))
154
return false;
155
if (size < header.length)
156
return false;
157
pos += header.length;
158
size -= header.length;
159
} while ((header.type != EFI_DEV_END_PATH && header.type != EFI_DEV_END_PATH2) ||
160
(header.sub_type != EFI_DEV_END_ENTIRE));
161
if (pos != (const void *)file_path_list + src->file_path_list_length)
162
return false;
163
164
dest->attributes = src->attributes;
165
dest->file_path_list_length = src->file_path_list_length;
166
dest->description = description;
167
dest->file_path_list = file_path_list;
168
dest->optional_data_size = size;
169
dest->optional_data = size ? pos : NULL;
170
171
return true;
172
}
173
174
/*
175
* At least some versions of Dell firmware pass the entire contents of the
176
* Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
177
* OptionalData field.
178
*
179
* Detect this case and extract OptionalData.
180
*/
181
void efi_apply_loadoptions_quirk(const void **load_options, u32 *load_options_size)
182
{
183
const efi_load_option_t *load_option = *load_options;
184
efi_load_option_unpacked_t load_option_unpacked;
185
186
if (!IS_ENABLED(CONFIG_X86))
187
return;
188
if (!load_option)
189
return;
190
if (*load_options_size < sizeof(*load_option))
191
return;
192
if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
193
return;
194
195
if (!efi_load_option_unpack(&load_option_unpacked, load_option, *load_options_size))
196
return;
197
198
efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
199
efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
200
201
*load_options = load_option_unpacked.optional_data;
202
*load_options_size = load_option_unpacked.optional_data_size;
203
}
204
205
enum efistub_event_type {
206
EFISTUB_EVT_INITRD,
207
EFISTUB_EVT_LOAD_OPTIONS,
208
EFISTUB_EVT_COUNT,
209
};
210
211
#define STR_WITH_SIZE(s) sizeof(s), s
212
213
static const struct {
214
u32 pcr_index;
215
u32 event_id;
216
u32 event_data_len;
217
u8 event_data[52];
218
} events[] = {
219
[EFISTUB_EVT_INITRD] = {
220
9,
221
INITRD_EVENT_TAG_ID,
222
STR_WITH_SIZE("Linux initrd")
223
},
224
[EFISTUB_EVT_LOAD_OPTIONS] = {
225
9,
226
LOAD_OPTIONS_EVENT_TAG_ID,
227
STR_WITH_SIZE("LOADED_IMAGE::LoadOptions")
228
},
229
};
230
231
static_assert(sizeof(efi_tcg2_event_t) == sizeof(efi_cc_event_t));
232
233
union efistub_event {
234
efi_tcg2_event_t tcg2_data;
235
efi_cc_event_t cc_data;
236
};
237
238
struct efistub_measured_event {
239
union efistub_event event_data;
240
TCG_PCClientTaggedEvent tagged_event __packed;
241
};
242
243
static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
244
unsigned long load_size,
245
enum efistub_event_type event)
246
{
247
union {
248
efi_status_t
249
(__efiapi *hash_log_extend_event)(void *, u64, efi_physical_addr_t,
250
u64, const union efistub_event *);
251
struct { u32 hash_log_extend_event; } mixed_mode;
252
} method;
253
struct efistub_measured_event *evt __free(efi_pool) = NULL;
254
int size = struct_size(evt, tagged_event.tagged_event_data,
255
events[event].event_data_len);
256
efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
257
efi_tcg2_protocol_t *tcg2 = NULL;
258
union efistub_event ev;
259
efi_status_t status;
260
void *protocol;
261
262
efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2);
263
if (tcg2) {
264
ev.tcg2_data = (struct efi_tcg2_event){
265
.event_size = size,
266
.event_header.header_size = sizeof(ev.tcg2_data.event_header),
267
.event_header.header_version = EFI_TCG2_EVENT_HEADER_VERSION,
268
.event_header.pcr_index = events[event].pcr_index,
269
.event_header.event_type = EV_EVENT_TAG,
270
};
271
protocol = tcg2;
272
method.hash_log_extend_event =
273
(void *)efi_table_attr(tcg2, hash_log_extend_event);
274
} else {
275
efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID;
276
efi_cc_protocol_t *cc = NULL;
277
278
efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc);
279
if (!cc)
280
return EFI_UNSUPPORTED;
281
282
ev.cc_data = (struct efi_cc_event){
283
.event_size = size,
284
.event_header.header_size = sizeof(ev.cc_data.event_header),
285
.event_header.header_version = EFI_CC_EVENT_HEADER_VERSION,
286
.event_header.event_type = EV_EVENT_TAG,
287
};
288
289
status = efi_call_proto(cc, map_pcr_to_mr_index,
290
events[event].pcr_index,
291
&ev.cc_data.event_header.mr_index);
292
if (status != EFI_SUCCESS)
293
goto fail;
294
295
protocol = cc;
296
method.hash_log_extend_event =
297
(void *)efi_table_attr(cc, hash_log_extend_event);
298
}
299
300
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, (void **)&evt);
301
if (status != EFI_SUCCESS)
302
goto fail;
303
304
*evt = (struct efistub_measured_event) {
305
.event_data = ev,
306
.tagged_event.tagged_event_id = events[event].event_id,
307
.tagged_event.tagged_event_data_size = events[event].event_data_len,
308
};
309
310
memcpy(evt->tagged_event.tagged_event_data, events[event].event_data,
311
events[event].event_data_len);
312
313
status = efi_fn_call(&method, hash_log_extend_event, protocol, 0,
314
load_addr, load_size, &evt->event_data);
315
316
if (status == EFI_SUCCESS)
317
return EFI_SUCCESS;
318
319
fail:
320
efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status);
321
return status;
322
}
323
324
/*
325
* Convert the unicode UEFI command line to ASCII to pass to kernel.
326
* Size of memory allocated return in *cmd_line_len.
327
* Returns NULL on error.
328
*/
329
char *efi_convert_cmdline(efi_loaded_image_t *image)
330
{
331
const efi_char16_t *options = efi_table_attr(image, load_options);
332
u32 options_size = efi_table_attr(image, load_options_size);
333
int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
334
unsigned long cmdline_addr = 0;
335
const efi_char16_t *s2;
336
bool in_quote = false;
337
efi_status_t status;
338
u32 options_chars;
339
340
if (options_size > 0)
341
efi_measure_tagged_event((unsigned long)options, options_size,
342
EFISTUB_EVT_LOAD_OPTIONS);
343
344
efi_apply_loadoptions_quirk((const void **)&options, &options_size);
345
options_chars = options_size / sizeof(efi_char16_t);
346
347
if (options) {
348
s2 = options;
349
while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
350
efi_char16_t c = *s2++;
351
352
if (c < 0x80) {
353
if (c == L'\0' || c == L'\n')
354
break;
355
if (c == L'"')
356
in_quote = !in_quote;
357
else if (!in_quote && isspace((char)c))
358
safe_options_bytes = options_bytes;
359
360
options_bytes++;
361
continue;
362
}
363
364
/*
365
* Get the number of UTF-8 bytes corresponding to a
366
* UTF-16 character.
367
* The first part handles everything in the BMP.
368
*/
369
options_bytes += 2 + (c >= 0x800);
370
/*
371
* Add one more byte for valid surrogate pairs. Invalid
372
* surrogates will be replaced with 0xfffd and take up
373
* only 3 bytes.
374
*/
375
if ((c & 0xfc00) == 0xd800) {
376
/*
377
* If the very last word is a high surrogate,
378
* we must ignore it since we can't access the
379
* low surrogate.
380
*/
381
if (!options_chars) {
382
options_bytes -= 3;
383
} else if ((*s2 & 0xfc00) == 0xdc00) {
384
options_bytes++;
385
options_chars--;
386
s2++;
387
}
388
}
389
}
390
if (options_bytes >= COMMAND_LINE_SIZE) {
391
options_bytes = safe_options_bytes;
392
efi_err("Command line is too long: truncated to %d bytes\n",
393
options_bytes);
394
}
395
}
396
397
options_bytes++; /* NUL termination */
398
399
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes,
400
(void **)&cmdline_addr);
401
if (status != EFI_SUCCESS)
402
return NULL;
403
404
snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
405
options_bytes - 1, options);
406
407
return (char *)cmdline_addr;
408
}
409
410
/**
411
* efi_exit_boot_services() - Exit boot services
412
* @handle: handle of the exiting image
413
* @priv: argument to be passed to @priv_func
414
* @priv_func: function to process the memory map before exiting boot services
415
*
416
* Handle calling ExitBootServices according to the requirements set out by the
417
* spec. Obtains the current memory map, and returns that info after calling
418
* ExitBootServices. The client must specify a function to perform any
419
* processing of the memory map data prior to ExitBootServices. A client
420
* specific structure may be passed to the function via priv. The client
421
* function may be called multiple times.
422
*
423
* Return: status code
424
*/
425
efi_status_t efi_exit_boot_services(void *handle, void *priv,
426
efi_exit_boot_map_processing priv_func)
427
{
428
struct efi_boot_memmap *map;
429
efi_status_t status;
430
431
if (efi_disable_pci_dma)
432
efi_pci_disable_bridge_busmaster();
433
434
status = efi_get_memory_map(&map, true);
435
if (status != EFI_SUCCESS)
436
return status;
437
438
status = priv_func(map, priv);
439
if (status != EFI_SUCCESS) {
440
efi_bs_call(free_pool, map);
441
return status;
442
}
443
444
status = efi_bs_call(exit_boot_services, handle, map->map_key);
445
446
if (status == EFI_INVALID_PARAMETER) {
447
/*
448
* The memory map changed between efi_get_memory_map() and
449
* exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
450
* EFI_BOOT_SERVICES.ExitBootServices we need to get the
451
* updated map, and try again. The spec implies one retry
452
* should be sufficent, which is confirmed against the EDK2
453
* implementation. Per the spec, we can only invoke
454
* get_memory_map() and exit_boot_services() - we cannot alloc
455
* so efi_get_memory_map() cannot be used, and we must reuse
456
* the buffer. For all practical purposes, the headroom in the
457
* buffer should account for any changes in the map so the call
458
* to get_memory_map() is expected to succeed here.
459
*/
460
map->map_size = map->buff_size;
461
status = efi_bs_call(get_memory_map,
462
&map->map_size,
463
&map->map,
464
&map->map_key,
465
&map->desc_size,
466
&map->desc_ver);
467
468
/* exit_boot_services() was called, thus cannot free */
469
if (status != EFI_SUCCESS)
470
return status;
471
472
status = priv_func(map, priv);
473
/* exit_boot_services() was called, thus cannot free */
474
if (status != EFI_SUCCESS)
475
return status;
476
477
status = efi_bs_call(exit_boot_services, handle, map->map_key);
478
}
479
480
return status;
481
}
482
483
/**
484
* get_efi_config_table() - retrieve UEFI configuration table
485
* @guid: GUID of the configuration table to be retrieved
486
* Return: pointer to the configuration table or NULL
487
*/
488
void *get_efi_config_table(efi_guid_t guid)
489
{
490
unsigned long tables = efi_table_attr(efi_system_table, tables);
491
int nr_tables = efi_table_attr(efi_system_table, nr_tables);
492
int i;
493
494
for (i = 0; i < nr_tables; i++) {
495
efi_config_table_t *t = (void *)tables;
496
497
if (efi_guidcmp(t->guid, guid) == 0)
498
return efi_table_attr(t, table);
499
500
tables += efi_is_native() ? sizeof(efi_config_table_t)
501
: sizeof(efi_config_table_32_t);
502
}
503
return NULL;
504
}
505
506
/*
507
* The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
508
* for the firmware or bootloader to expose the initrd data directly to the stub
509
* via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is
510
* very easy to implement. It is a simple Linux initrd specific conduit between
511
* kernel and firmware, allowing us to put the EFI stub (being part of the
512
* kernel) in charge of where and when to load the initrd, while leaving it up
513
* to the firmware to decide whether it needs to expose its filesystem hierarchy
514
* via EFI protocols.
515
*/
516
static const struct {
517
struct efi_vendor_dev_path vendor;
518
struct efi_generic_dev_path end;
519
} __packed initrd_dev_path = {
520
{
521
{
522
EFI_DEV_MEDIA,
523
EFI_DEV_MEDIA_VENDOR,
524
sizeof(struct efi_vendor_dev_path),
525
},
526
LINUX_EFI_INITRD_MEDIA_GUID
527
}, {
528
EFI_DEV_END_PATH,
529
EFI_DEV_END_ENTIRE,
530
sizeof(struct efi_generic_dev_path)
531
}
532
};
533
534
/**
535
* efi_load_initrd_dev_path() - load the initrd from the Linux initrd device path
536
* @initrd: pointer of struct to store the address where the initrd was loaded
537
* and the size of the loaded initrd
538
* @max: upper limit for the initrd memory allocation
539
*
540
* Return:
541
* * %EFI_SUCCESS if the initrd was loaded successfully, in which
542
* case @load_addr and @load_size are assigned accordingly
543
* * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd device path
544
* * %EFI_OUT_OF_RESOURCES if memory allocation failed
545
* * %EFI_LOAD_ERROR in all other cases
546
*/
547
static
548
efi_status_t efi_load_initrd_dev_path(struct linux_efi_initrd *initrd,
549
unsigned long max)
550
{
551
efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
552
efi_device_path_protocol_t *dp;
553
efi_load_file2_protocol_t *lf2;
554
efi_handle_t handle;
555
efi_status_t status;
556
557
dp = (efi_device_path_protocol_t *)&initrd_dev_path;
558
status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
559
if (status != EFI_SUCCESS)
560
return status;
561
562
status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid,
563
(void **)&lf2);
564
if (status != EFI_SUCCESS)
565
return status;
566
567
initrd->size = 0;
568
status = efi_call_proto(lf2, load_file, dp, false, &initrd->size, NULL);
569
if (status != EFI_BUFFER_TOO_SMALL)
570
return EFI_LOAD_ERROR;
571
572
status = efi_allocate_pages(initrd->size, &initrd->base, max);
573
if (status != EFI_SUCCESS)
574
return status;
575
576
status = efi_call_proto(lf2, load_file, dp, false, &initrd->size,
577
(void *)initrd->base);
578
if (status != EFI_SUCCESS) {
579
efi_free(initrd->size, initrd->base);
580
return EFI_LOAD_ERROR;
581
}
582
return EFI_SUCCESS;
583
}
584
585
static
586
efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
587
struct linux_efi_initrd *initrd,
588
unsigned long soft_limit,
589
unsigned long hard_limit)
590
{
591
if (image == NULL)
592
return EFI_UNSUPPORTED;
593
594
return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
595
soft_limit, hard_limit,
596
&initrd->base, &initrd->size);
597
}
598
599
/**
600
* efi_load_initrd() - Load initial RAM disk
601
* @image: EFI loaded image protocol
602
* @soft_limit: preferred address for loading the initrd
603
* @hard_limit: upper limit address for loading the initrd
604
* @out: pointer to store the address of the initrd table
605
*
606
* Return: status code
607
*/
608
efi_status_t efi_load_initrd(efi_loaded_image_t *image,
609
unsigned long soft_limit,
610
unsigned long hard_limit,
611
const struct linux_efi_initrd **out)
612
{
613
efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
614
efi_status_t status = EFI_SUCCESS;
615
struct linux_efi_initrd initrd, *tbl;
616
617
if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || efi_noinitrd)
618
return EFI_SUCCESS;
619
620
status = efi_load_initrd_dev_path(&initrd, hard_limit);
621
if (status == EFI_SUCCESS) {
622
efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
623
} else if (status == EFI_NOT_FOUND) {
624
status = efi_load_initrd_cmdline(image, &initrd, soft_limit,
625
hard_limit);
626
/* command line loader disabled or no initrd= passed? */
627
if (status == EFI_UNSUPPORTED || status == EFI_NOT_READY)
628
return EFI_SUCCESS;
629
if (status == EFI_SUCCESS)
630
efi_info("Loaded initrd from command line option\n");
631
}
632
if (status != EFI_SUCCESS)
633
goto failed;
634
635
if (initrd.size > 0 &&
636
efi_measure_tagged_event(initrd.base, initrd.size,
637
EFISTUB_EVT_INITRD) == EFI_SUCCESS)
638
efi_info("Measured initrd data into PCR 9\n");
639
640
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(initrd),
641
(void **)&tbl);
642
if (status != EFI_SUCCESS)
643
goto free_initrd;
644
645
*tbl = initrd;
646
status = efi_bs_call(install_configuration_table, &tbl_guid, tbl);
647
if (status != EFI_SUCCESS)
648
goto free_tbl;
649
650
if (out)
651
*out = tbl;
652
return EFI_SUCCESS;
653
654
free_tbl:
655
efi_bs_call(free_pool, tbl);
656
free_initrd:
657
efi_free(initrd.size, initrd.base);
658
failed:
659
efi_err("Failed to load initrd: 0x%lx\n", status);
660
return status;
661
}
662
663
/**
664
* efi_wait_for_key() - Wait for key stroke
665
* @usec: number of microseconds to wait for key stroke
666
* @key: key entered
667
*
668
* Wait for up to @usec microseconds for a key stroke.
669
*
670
* Return: status code, EFI_SUCCESS if key received
671
*/
672
efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
673
{
674
efi_event_t events[2], timer;
675
unsigned long index;
676
efi_simple_text_input_protocol_t *con_in;
677
efi_status_t status;
678
679
con_in = efi_table_attr(efi_system_table, con_in);
680
if (!con_in)
681
return EFI_UNSUPPORTED;
682
efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key));
683
684
status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer);
685
if (status != EFI_SUCCESS)
686
return status;
687
688
status = efi_bs_call(set_timer, timer, EfiTimerRelative,
689
EFI_100NSEC_PER_USEC * usec);
690
if (status != EFI_SUCCESS)
691
return status;
692
efi_set_event_at(events, 1, timer);
693
694
status = efi_bs_call(wait_for_event, 2, events, &index);
695
if (status == EFI_SUCCESS) {
696
if (index == 0)
697
status = efi_call_proto(con_in, read_keystroke, key);
698
else
699
status = EFI_TIMEOUT;
700
}
701
702
efi_bs_call(close_event, timer);
703
704
return status;
705
}
706
707
/**
708
* efi_remap_image - Remap a loaded image with the appropriate permissions
709
* for code and data
710
*
711
* @image_base: the base of the image in memory
712
* @alloc_size: the size of the area in memory occupied by the image
713
* @code_size: the size of the leading part of the image containing code
714
* and read-only data
715
*
716
* efi_remap_image() uses the EFI memory attribute protocol to remap the code
717
* region of the loaded image read-only/executable, and the remainder
718
* read-write/non-executable. The code region is assumed to start at the base
719
* of the image, and will therefore cover the PE/COFF header as well.
720
*/
721
void efi_remap_image(unsigned long image_base, unsigned alloc_size,
722
unsigned long code_size)
723
{
724
efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
725
efi_memory_attribute_protocol_t *memattr;
726
efi_status_t status;
727
u64 attr;
728
729
/*
730
* If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's
731
* invoke it to remap the text/rodata region of the decompressed image
732
* as read-only and the data/bss region as non-executable.
733
*/
734
status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&memattr);
735
if (status != EFI_SUCCESS)
736
return;
737
738
// Get the current attributes for the entire region
739
status = memattr->get_memory_attributes(memattr, image_base,
740
alloc_size, &attr);
741
if (status != EFI_SUCCESS) {
742
efi_warn("Failed to retrieve memory attributes for image region: 0x%lx\n",
743
status);
744
return;
745
}
746
747
// Mark the code region as read-only
748
status = memattr->set_memory_attributes(memattr, image_base, code_size,
749
EFI_MEMORY_RO);
750
if (status != EFI_SUCCESS) {
751
efi_warn("Failed to remap code region read-only\n");
752
return;
753
}
754
755
// If the entire region was already mapped as non-exec, clear the
756
// attribute from the code region. Otherwise, set it on the data
757
// region.
758
if (attr & EFI_MEMORY_XP) {
759
status = memattr->clear_memory_attributes(memattr, image_base,
760
code_size,
761
EFI_MEMORY_XP);
762
if (status != EFI_SUCCESS)
763
efi_warn("Failed to remap code region executable\n");
764
} else {
765
status = memattr->set_memory_attributes(memattr,
766
image_base + code_size,
767
alloc_size - code_size,
768
EFI_MEMORY_XP);
769
if (status != EFI_SUCCESS)
770
efi_warn("Failed to remap data region non-executable\n");
771
}
772
}
773
774