blob: a449e645c44fbc50d3ea00443200e5e809e54724 [file] [log] [blame]
Thomas Gleixner55716d22019-06-01 10:08:42 +02001// SPDX-License-Identifier: GPL-2.0-only
Tom Gundersena9499fa2013-02-08 15:37:06 +00002/*
3 * efi.c - EFI subsystem
4 *
5 * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
6 * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
7 * Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
8 *
9 * This code registers /sys/firmware/efi{,/efivars} when EFI is supported,
10 * allowing the efivarfs to be mounted or the efivars module to be loaded.
11 * The existance of /sys/firmware/efi may also be used by userspace to
12 * determine that the system supports EFI.
Tom Gundersena9499fa2013-02-08 15:37:06 +000013 */
14
Leif Lindholm272686b2013-09-05 11:34:54 +010015#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
Tom Gundersena9499fa2013-02-08 15:37:06 +000017#include <linux/kobject.h>
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/device.h>
21#include <linux/efi.h>
Mark Salter0302f712013-12-30 12:12:12 -050022#include <linux/of.h>
23#include <linux/of_fdt.h>
Leif Lindholm272686b2013-09-05 11:34:54 +010024#include <linux/io.h>
Ard Biesheuvel63625982016-11-12 21:32:31 +000025#include <linux/kexec.h>
Lee, Chun-Yi28d54022014-07-09 18:39:29 +080026#include <linux/platform_device.h>
Ard Biesheuvel63625982016-11-12 21:32:31 +000027#include <linux/random.h>
28#include <linux/reboot.h>
Octavian Purdila475fb4e2016-07-08 19:13:12 +030029#include <linux/slab.h>
30#include <linux/acpi.h>
31#include <linux/ucs2_string.h>
Matt Fleming816e7612016-02-29 21:22:52 +000032#include <linux/memblock.h>
Leif Lindholm272686b2013-09-05 11:34:54 +010033
Ard Biesheuvel0f7f2f02016-01-12 14:22:46 +010034#include <asm/early_ioremap.h>
Ard Biesheuvelf7d92482015-11-30 13:28:19 +010035
Leif Lindholm272686b2013-09-05 11:34:54 +010036struct efi __read_mostly efi = {
Ard Biesheuvelbf924862015-09-09 10:08:15 +020037 .mps = EFI_INVALID_TABLE_ADDR,
38 .acpi = EFI_INVALID_TABLE_ADDR,
39 .acpi20 = EFI_INVALID_TABLE_ADDR,
40 .smbios = EFI_INVALID_TABLE_ADDR,
41 .smbios3 = EFI_INVALID_TABLE_ADDR,
42 .sal_systab = EFI_INVALID_TABLE_ADDR,
43 .boot_info = EFI_INVALID_TABLE_ADDR,
44 .hcdp = EFI_INVALID_TABLE_ADDR,
45 .uga = EFI_INVALID_TABLE_ADDR,
46 .uv_systab = EFI_INVALID_TABLE_ADDR,
47 .fw_vendor = EFI_INVALID_TABLE_ADDR,
48 .runtime = EFI_INVALID_TABLE_ADDR,
49 .config_table = EFI_INVALID_TABLE_ADDR,
50 .esrt = EFI_INVALID_TABLE_ADDR,
51 .properties_table = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvela604af02016-04-25 21:06:44 +010052 .mem_attr_table = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvel63625982016-11-12 21:32:31 +000053 .rng_seed = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvel71e09402018-09-21 09:32:44 -070054 .tpm_log = EFI_INVALID_TABLE_ADDR,
Matthew Garrettc46f3402019-05-20 13:54:59 -070055 .tpm_final_log = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvel71e09402018-09-21 09:32:44 -070056 .mem_reserve = EFI_INVALID_TABLE_ADDR,
Leif Lindholm272686b2013-09-05 11:34:54 +010057};
58EXPORT_SYMBOL(efi);
Tom Gundersena9499fa2013-02-08 15:37:06 +000059
Tom Lendackya19d66c2017-07-17 16:10:13 -050060static unsigned long *efi_tables[] = {
61 &efi.mps,
62 &efi.acpi,
63 &efi.acpi20,
64 &efi.smbios,
65 &efi.smbios3,
66 &efi.sal_systab,
67 &efi.boot_info,
68 &efi.hcdp,
69 &efi.uga,
70 &efi.uv_systab,
71 &efi.fw_vendor,
72 &efi.runtime,
73 &efi.config_table,
74 &efi.esrt,
75 &efi.properties_table,
76 &efi.mem_attr_table,
77};
78
Sai Praneeth7e904a92018-03-12 08:44:56 +000079struct mm_struct efi_mm = {
80 .mm_rb = RB_ROOT,
81 .mm_users = ATOMIC_INIT(2),
82 .mm_count = ATOMIC_INIT(1),
83 .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
84 .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
85 .mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
Rik van Rielc1a2f7f2018-07-16 15:03:31 -040086 .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0},
Sai Praneeth7e904a92018-03-12 08:44:56 +000087};
88
Sai Praneeth3eb420e2018-07-11 11:40:35 +020089struct workqueue_struct *efi_rts_wq;
90
Dave Youngb2e0a542014-08-14 17:15:26 +080091static bool disable_runtime;
92static int __init setup_noefi(char *arg)
93{
94 disable_runtime = true;
95 return 0;
96}
97early_param("noefi", setup_noefi);
98
99bool efi_runtime_disabled(void)
100{
101 return disable_runtime;
102}
103
Dave Young5ae36832014-08-14 17:15:28 +0800104static int __init parse_efi_cmdline(char *str)
105{
Ricardo Neri9115c752015-07-15 19:36:03 -0700106 if (!str) {
107 pr_warn("need at least one option\n");
108 return -EINVAL;
109 }
110
Leif Lindholm12dd00e2015-08-26 14:24:56 +0100111 if (parse_option_str(str, "debug"))
112 set_bit(EFI_DBG, &efi.flags);
113
Dave Young5ae36832014-08-14 17:15:28 +0800114 if (parse_option_str(str, "noruntime"))
115 disable_runtime = true;
116
117 return 0;
118}
119early_param("efi", parse_efi_cmdline);
120
Peter Jones0bb54902015-04-28 18:44:31 -0400121struct kobject *efi_kobj;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000122
123/*
124 * Let's not leave out systab information that snuck into
125 * the efivars driver
Dave Young0b02e442017-12-06 09:50:10 +0000126 * Note, do not add more fields in systab sysfs file as it breaks sysfs
127 * one value per file rule!
Tom Gundersena9499fa2013-02-08 15:37:06 +0000128 */
129static ssize_t systab_show(struct kobject *kobj,
130 struct kobj_attribute *attr, char *buf)
131{
132 char *str = buf;
133
134 if (!kobj || !buf)
135 return -EINVAL;
136
137 if (efi.mps != EFI_INVALID_TABLE_ADDR)
138 str += sprintf(str, "MPS=0x%lx\n", efi.mps);
139 if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
140 str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
141 if (efi.acpi != EFI_INVALID_TABLE_ADDR)
142 str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
Jean Delvareb119fe02015-04-30 15:23:05 +0200143 /*
144 * If both SMBIOS and SMBIOS3 entry points are implemented, the
145 * SMBIOS3 entry point shall be preferred, so we list it first to
146 * let applications stop parsing after the first match.
147 */
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200148 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
149 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
Jean Delvareb119fe02015-04-30 15:23:05 +0200150 if (efi.smbios != EFI_INVALID_TABLE_ADDR)
151 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
Tom Gundersena9499fa2013-02-08 15:37:06 +0000152 if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
153 str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
154 if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
155 str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
156 if (efi.uga != EFI_INVALID_TABLE_ADDR)
157 str += sprintf(str, "UGA=0x%lx\n", efi.uga);
158
159 return str - buf;
160}
161
Greg Kroah-Hartmanaf97a772017-12-06 09:50:08 +0000162static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
Tom Gundersena9499fa2013-02-08 15:37:06 +0000163
Dave Younga0998eb2013-12-20 18:02:17 +0800164#define EFI_FIELD(var) efi.var
165
166#define EFI_ATTR_SHOW(name) \
167static ssize_t name##_show(struct kobject *kobj, \
168 struct kobj_attribute *attr, char *buf) \
169{ \
170 return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
171}
172
173EFI_ATTR_SHOW(fw_vendor);
174EFI_ATTR_SHOW(runtime);
175EFI_ATTR_SHOW(config_table);
176
Steve McIntyre2859dff2015-01-09 15:29:53 +0000177static ssize_t fw_platform_size_show(struct kobject *kobj,
178 struct kobj_attribute *attr, char *buf)
179{
180 return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
181}
182
Dave Younga0998eb2013-12-20 18:02:17 +0800183static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
184static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
185static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
Steve McIntyre2859dff2015-01-09 15:29:53 +0000186static struct kobj_attribute efi_attr_fw_platform_size =
187 __ATTR_RO(fw_platform_size);
Dave Younga0998eb2013-12-20 18:02:17 +0800188
Tom Gundersena9499fa2013-02-08 15:37:06 +0000189static struct attribute *efi_subsys_attrs[] = {
190 &efi_attr_systab.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800191 &efi_attr_fw_vendor.attr,
192 &efi_attr_runtime.attr,
193 &efi_attr_config_table.attr,
Steve McIntyre2859dff2015-01-09 15:29:53 +0000194 &efi_attr_fw_platform_size.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800195 NULL,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000196};
197
Dave Younga0998eb2013-12-20 18:02:17 +0800198static umode_t efi_attr_is_visible(struct kobject *kobj,
199 struct attribute *attr, int n)
200{
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200201 if (attr == &efi_attr_fw_vendor.attr) {
202 if (efi_enabled(EFI_PARAVIRT) ||
203 efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
204 return 0;
205 } else if (attr == &efi_attr_runtime.attr) {
206 if (efi.runtime == EFI_INVALID_TABLE_ADDR)
207 return 0;
208 } else if (attr == &efi_attr_config_table.attr) {
209 if (efi.config_table == EFI_INVALID_TABLE_ADDR)
210 return 0;
211 }
Dave Younga0998eb2013-12-20 18:02:17 +0800212
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200213 return attr->mode;
Dave Younga0998eb2013-12-20 18:02:17 +0800214}
215
Arvind Yadav3ad6bd72017-08-18 20:49:46 +0100216static const struct attribute_group efi_subsys_attr_group = {
Tom Gundersena9499fa2013-02-08 15:37:06 +0000217 .attrs = efi_subsys_attrs,
Dave Younga0998eb2013-12-20 18:02:17 +0800218 .is_visible = efi_attr_is_visible,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000219};
220
221static struct efivars generic_efivars;
222static struct efivar_operations generic_ops;
223
224static int generic_ops_register(void)
225{
226 generic_ops.get_variable = efi.get_variable;
227 generic_ops.set_variable = efi.set_variable;
Ard Biesheuvel9c6672a2016-02-01 22:06:55 +0000228 generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000229 generic_ops.get_next_variable = efi.get_next_variable;
Matt Fleminga614e192013-04-30 11:30:24 +0100230 generic_ops.query_variable_store = efi_query_variable_store;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000231
232 return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
233}
234
235static void generic_ops_unregister(void)
236{
237 efivars_unregister(&generic_efivars);
238}
239
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300240#if IS_ENABLED(CONFIG_ACPI)
241#define EFIVAR_SSDT_NAME_MAX 16
242static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
243static int __init efivar_ssdt_setup(char *str)
244{
245 if (strlen(str) < sizeof(efivar_ssdt))
246 memcpy(efivar_ssdt, str, strlen(str));
247 else
248 pr_warn("efivar_ssdt: name too long: %s\n", str);
249 return 0;
250}
251__setup("efivar_ssdt=", efivar_ssdt_setup);
252
253static __init int efivar_ssdt_iter(efi_char16_t *name, efi_guid_t vendor,
254 unsigned long name_size, void *data)
255{
256 struct efivar_entry *entry;
257 struct list_head *list = data;
258 char utf8_name[EFIVAR_SSDT_NAME_MAX];
259 int limit = min_t(unsigned long, EFIVAR_SSDT_NAME_MAX, name_size);
260
261 ucs2_as_utf8(utf8_name, name, limit - 1);
262 if (strncmp(utf8_name, efivar_ssdt, limit) != 0)
263 return 0;
264
265 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
266 if (!entry)
267 return 0;
268
269 memcpy(entry->var.VariableName, name, name_size);
270 memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t));
271
272 efivar_entry_add(entry, list);
273
274 return 0;
275}
276
277static __init int efivar_ssdt_load(void)
278{
279 LIST_HEAD(entries);
280 struct efivar_entry *entry, *aux;
281 unsigned long size;
282 void *data;
283 int ret;
284
285 ret = efivar_init(efivar_ssdt_iter, &entries, true, &entries);
286
287 list_for_each_entry_safe(entry, aux, &entries, list) {
288 pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt,
289 &entry->var.VendorGuid);
290
291 list_del(&entry->list);
292
293 ret = efivar_entry_size(entry, &size);
294 if (ret) {
295 pr_err("failed to get var size\n");
296 goto free_entry;
297 }
298
299 data = kmalloc(size, GFP_KERNEL);
Dan Carpentera75dcb52016-10-18 15:33:18 +0100300 if (!data) {
301 ret = -ENOMEM;
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300302 goto free_entry;
Dan Carpentera75dcb52016-10-18 15:33:18 +0100303 }
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300304
305 ret = efivar_entry_get(entry, NULL, &size, data);
306 if (ret) {
307 pr_err("failed to get var data\n");
308 goto free_data;
309 }
310
311 ret = acpi_load_table(data);
312 if (ret) {
313 pr_err("failed to load table: %d\n", ret);
314 goto free_data;
315 }
316
317 goto free_entry;
318
319free_data:
320 kfree(data);
321
322free_entry:
323 kfree(entry);
324 }
325
326 return ret;
327}
328#else
329static inline int efivar_ssdt_load(void) { return 0; }
330#endif
331
Tom Gundersena9499fa2013-02-08 15:37:06 +0000332/*
333 * We register the efi subsystem with the firmware subsystem and the
334 * efivars subsystem with the efi subsystem, if the system was booted with
335 * EFI.
336 */
337static int __init efisubsys_init(void)
338{
339 int error;
340
341 if (!efi_enabled(EFI_BOOT))
342 return 0;
343
Sai Praneeth3eb420e2018-07-11 11:40:35 +0200344 /*
345 * Since we process only one efi_runtime_service() at a time, an
346 * ordered workqueue (which creates only one execution context)
347 * should suffice all our needs.
348 */
349 efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
350 if (!efi_rts_wq) {
351 pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
352 clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
353 return 0;
354 }
355
Tom Gundersena9499fa2013-02-08 15:37:06 +0000356 /* We register the efi directory at /sys/firmware/efi */
357 efi_kobj = kobject_create_and_add("efi", firmware_kobj);
358 if (!efi_kobj) {
359 pr_err("efi: Firmware registration failed.\n");
360 return -ENOMEM;
361 }
362
363 error = generic_ops_register();
364 if (error)
365 goto err_put;
366
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300367 if (efi_enabled(EFI_RUNTIME_SERVICES))
368 efivar_ssdt_load();
369
Tom Gundersena9499fa2013-02-08 15:37:06 +0000370 error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
371 if (error) {
372 pr_err("efi: Sysfs attribute export failed with error %d.\n",
373 error);
374 goto err_unregister;
375 }
376
Dave Young926172d2013-12-20 18:02:18 +0800377 error = efi_runtime_map_init(efi_kobj);
378 if (error)
379 goto err_remove_group;
380
Tom Gundersena9499fa2013-02-08 15:37:06 +0000381 /* and the standard mountpoint for efivarfs */
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -0500382 error = sysfs_create_mount_point(efi_kobj, "efivars");
383 if (error) {
Tom Gundersena9499fa2013-02-08 15:37:06 +0000384 pr_err("efivars: Subsystem registration failed.\n");
Tom Gundersena9499fa2013-02-08 15:37:06 +0000385 goto err_remove_group;
386 }
387
388 return 0;
389
390err_remove_group:
391 sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
392err_unregister:
393 generic_ops_unregister();
394err_put:
395 kobject_put(efi_kobj);
396 return error;
397}
398
399subsys_initcall(efisubsys_init);
Leif Lindholm272686b2013-09-05 11:34:54 +0100400
Peter Jones0bb54902015-04-28 18:44:31 -0400401/*
402 * Find the efi memory descriptor for a given physical address. Given a
Matt Flemingdca0f972016-02-27 15:52:50 +0000403 * physical address, determine if it exists within an EFI Memory Map entry,
Peter Jones0bb54902015-04-28 18:44:31 -0400404 * and if so, populate the supplied memory descriptor with the appropriate
405 * data.
406 */
Ard Biesheuvel7e1550b2018-07-11 11:40:39 +0200407int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
Peter Jones0bb54902015-04-28 18:44:31 -0400408{
Matt Flemingdca0f972016-02-27 15:52:50 +0000409 efi_memory_desc_t *md;
Peter Jones0bb54902015-04-28 18:44:31 -0400410
411 if (!efi_enabled(EFI_MEMMAP)) {
412 pr_err_once("EFI_MEMMAP is not enabled.\n");
413 return -EINVAL;
414 }
415
Peter Jones0bb54902015-04-28 18:44:31 -0400416 if (!out_md) {
417 pr_err_once("out_md is null.\n");
418 return -EINVAL;
419 }
Peter Jones0bb54902015-04-28 18:44:31 -0400420
Matt Flemingdca0f972016-02-27 15:52:50 +0000421 for_each_efi_memory_desc(md) {
Peter Jones0bb54902015-04-28 18:44:31 -0400422 u64 size;
423 u64 end;
424
Peter Jones0bb54902015-04-28 18:44:31 -0400425 size = md->num_pages << EFI_PAGE_SHIFT;
426 end = md->phys_addr + size;
427 if (phys_addr >= md->phys_addr && phys_addr < end) {
428 memcpy(out_md, md, sizeof(*out_md));
Peter Jones0bb54902015-04-28 18:44:31 -0400429 return 0;
430 }
Peter Jones0bb54902015-04-28 18:44:31 -0400431 }
Peter Jones0bb54902015-04-28 18:44:31 -0400432 return -ENOENT;
433}
434
435/*
436 * Calculate the highest address of an efi memory descriptor.
437 */
438u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
439{
440 u64 size = md->num_pages << EFI_PAGE_SHIFT;
441 u64 end = md->phys_addr + size;
442 return end;
443}
Leif Lindholm272686b2013-09-05 11:34:54 +0100444
Matt Fleming816e7612016-02-29 21:22:52 +0000445void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {}
446
447/**
448 * efi_mem_reserve - Reserve an EFI memory region
449 * @addr: Physical address to reserve
450 * @size: Size of reservation
451 *
452 * Mark a region as reserved from general kernel allocation and
453 * prevent it being released by efi_free_boot_services().
454 *
455 * This function should be called drivers once they've parsed EFI
456 * configuration tables to figure out where their data lives, e.g.
457 * efi_esrt_init().
458 */
459void __init efi_mem_reserve(phys_addr_t addr, u64 size)
460{
461 if (!memblock_is_region_reserved(addr, size))
462 memblock_reserve(addr, size);
463
464 /*
465 * Some architectures (x86) reserve all boot services ranges
466 * until efi_free_boot_services() because of buggy firmware
467 * implementations. This means the above memblock_reserve() is
468 * superfluous on x86 and instead what it needs to do is
469 * ensure the @start, @size is not freed.
470 */
471 efi_arch_mem_reserve(addr, size);
472}
473
Leif Lindholm272686b2013-09-05 11:34:54 +0100474static __initdata efi_config_table_type_t common_tables[] = {
475 {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
476 {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
477 {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
478 {MPS_TABLE_GUID, "MPS", &efi.mps},
479 {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
480 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200481 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
Leif Lindholm272686b2013-09-05 11:34:54 +0100482 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
Peter Jones0bb54902015-04-28 18:44:31 -0400483 {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
Ard Biesheuvelbf924862015-09-09 10:08:15 +0200484 {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
Ard Biesheuvela604af02016-04-25 21:06:44 +0100485 {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
Ard Biesheuvel63625982016-11-12 21:32:31 +0000486 {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
Thiebaud Weksteen33b6d032017-09-20 10:13:39 +0200487 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
Matthew Garrettc46f3402019-05-20 13:54:59 -0700488 {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700489 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
Daeseok Youn69e60842014-02-13 17:16:36 +0900490 {NULL_GUID, NULL, NULL},
Leif Lindholm272686b2013-09-05 11:34:54 +0100491};
492
493static __init int match_config_table(efi_guid_t *guid,
494 unsigned long table,
495 efi_config_table_type_t *table_types)
496{
Leif Lindholm272686b2013-09-05 11:34:54 +0100497 int i;
498
499 if (table_types) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100500 for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100501 if (!efi_guidcmp(*guid, table_types[i].guid)) {
502 *(table_types[i].ptr) = table;
Ard Biesheuvel801820b2016-04-25 21:06:53 +0100503 if (table_types[i].name)
504 pr_cont(" %s=0x%lx ",
505 table_types[i].name, table);
Leif Lindholm272686b2013-09-05 11:34:54 +0100506 return 1;
507 }
508 }
509 }
510
511 return 0;
512}
513
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200514int __init efi_config_parse_tables(void *config_tables, int count, int sz,
515 efi_config_table_type_t *arch_tables)
516{
517 void *tablep;
518 int i;
519
520 tablep = config_tables;
521 pr_info("");
522 for (i = 0; i < count; i++) {
523 efi_guid_t guid;
524 unsigned long table;
525
526 if (efi_enabled(EFI_64BIT)) {
527 u64 table64;
528 guid = ((efi_config_table_64_t *)tablep)->guid;
529 table64 = ((efi_config_table_64_t *)tablep)->table;
530 table = table64;
531#ifndef CONFIG_64BIT
532 if (table64 >> 32) {
533 pr_cont("\n");
534 pr_err("Table located above 4GB, disabling EFI.\n");
535 return -EINVAL;
536 }
537#endif
538 } else {
539 guid = ((efi_config_table_32_t *)tablep)->guid;
540 table = ((efi_config_table_32_t *)tablep)->table;
541 }
542
543 if (!match_config_table(&guid, table, common_tables))
544 match_config_table(&guid, table, arch_tables);
545
546 tablep += sz;
547 }
548 pr_cont("\n");
549 set_bit(EFI_CONFIG_TABLES, &efi.flags);
Ard Biesheuvela1041712015-09-23 07:29:34 -0700550
Ard Biesheuvel63625982016-11-12 21:32:31 +0000551 if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
552 struct linux_efi_random_seed *seed;
553 u32 size = 0;
554
555 seed = early_memremap(efi.rng_seed, sizeof(*seed));
556 if (seed != NULL) {
557 size = seed->size;
558 early_memunmap(seed, sizeof(*seed));
559 } else {
560 pr_err("Could not map UEFI random seed!\n");
561 }
562 if (size > 0) {
563 seed = early_memremap(efi.rng_seed,
564 sizeof(*seed) + size);
565 if (seed != NULL) {
Ard Biesheuvel5b4e4c32018-03-08 08:00:18 +0000566 pr_notice("seeding entropy pool\n");
Ard Biesheuvel63625982016-11-12 21:32:31 +0000567 add_device_randomness(seed->bits, seed->size);
568 early_memunmap(seed, sizeof(*seed) + size);
569 } else {
570 pr_err("Could not map UEFI random seed!\n");
571 }
572 }
573 }
574
Daniel Kiper457ea3f2017-06-22 12:51:36 +0200575 if (efi_enabled(EFI_MEMMAP))
576 efi_memattr_init();
Sai Praneeth3a6b6c62017-01-31 13:21:35 +0000577
Thiebaud Weksteen33b6d032017-09-20 10:13:39 +0200578 efi_tpm_eventlog_init();
579
Ard Biesheuvela1041712015-09-23 07:29:34 -0700580 /* Parse the EFI Properties table if it exists */
581 if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
582 efi_properties_table_t *tbl;
583
584 tbl = early_memremap(efi.properties_table, sizeof(*tbl));
585 if (tbl == NULL) {
586 pr_err("Could not map Properties table!\n");
587 return -ENOMEM;
588 }
589
590 if (tbl->memory_protection_attribute &
591 EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
592 set_bit(EFI_NX_PE_DATA, &efi.flags);
593
594 early_memunmap(tbl, sizeof(*tbl));
595 }
596
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700597 if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) {
598 unsigned long prsv = efi.mem_reserve;
599
600 while (prsv) {
601 struct linux_efi_memreserve *rsv;
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100602 u8 *p;
603 int i;
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700604
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100605 /*
606 * Just map a full page: that is what we will get
607 * anyway, and it permits us to map the entire entry
608 * before knowing its size.
609 */
610 p = early_memremap(ALIGN_DOWN(prsv, PAGE_SIZE),
611 PAGE_SIZE);
612 if (p == NULL) {
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700613 pr_err("Could not map UEFI memreserve entry!\n");
614 return -ENOMEM;
615 }
616
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100617 rsv = (void *)(p + prsv % PAGE_SIZE);
618
619 /* reserve the entry itself */
620 memblock_reserve(prsv, EFI_MEMRESERVE_SIZE(rsv->size));
621
622 for (i = 0; i < atomic_read(&rsv->count); i++) {
623 memblock_reserve(rsv->entry[i].base,
624 rsv->entry[i].size);
625 }
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700626
627 prsv = rsv->next;
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100628 early_memunmap(p, PAGE_SIZE);
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700629 }
630 }
631
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200632 return 0;
633}
634
Leif Lindholm272686b2013-09-05 11:34:54 +0100635int __init efi_config_init(efi_config_table_type_t *arch_tables)
636{
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200637 void *config_tables;
638 int sz, ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100639
Rob Bradford88447c52019-05-25 13:25:59 +0200640 if (efi.systab->nr_tables == 0)
641 return 0;
642
Leif Lindholm272686b2013-09-05 11:34:54 +0100643 if (efi_enabled(EFI_64BIT))
644 sz = sizeof(efi_config_table_64_t);
645 else
646 sz = sizeof(efi_config_table_32_t);
647
648 /*
649 * Let's see what config tables the firmware passed to us.
650 */
651 config_tables = early_memremap(efi.systab->tables,
652 efi.systab->nr_tables * sz);
653 if (config_tables == NULL) {
654 pr_err("Could not map Configuration table!\n");
655 return -ENOMEM;
656 }
657
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200658 ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
659 arch_tables);
Leif Lindholm272686b2013-09-05 11:34:54 +0100660
Daniel Kiperabc93f82014-06-30 19:52:56 +0200661 early_memunmap(config_tables, efi.systab->nr_tables * sz);
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200662 return ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100663}
Mark Salter0302f712013-12-30 12:12:12 -0500664
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800665#ifdef CONFIG_EFI_VARS_MODULE
666static int __init efi_load_efivars(void)
667{
668 struct platform_device *pdev;
669
670 if (!efi_enabled(EFI_RUNTIME_SERVICES))
671 return 0;
672
673 pdev = platform_device_register_simple("efivars", 0, NULL, 0);
Vasyl Gomonovych50342b22018-01-02 18:10:40 +0000674 return PTR_ERR_OR_ZERO(pdev);
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800675}
676device_initcall(efi_load_efivars);
677#endif
678
Mark Salter0302f712013-12-30 12:12:12 -0500679#ifdef CONFIG_EFI_PARAMS_FROM_FDT
680
681#define UEFI_PARAM(name, prop, field) \
682 { \
683 { name }, \
684 { prop }, \
685 offsetof(struct efi_fdt_params, field), \
686 FIELD_SIZEOF(struct efi_fdt_params, field) \
687 }
688
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800689struct params {
Mark Salter0302f712013-12-30 12:12:12 -0500690 const char name[32];
691 const char propname[32];
692 int offset;
693 int size;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800694};
695
696static __initdata struct params fdt_params[] = {
Mark Salter0302f712013-12-30 12:12:12 -0500697 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
698 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
699 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
700 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
701 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
702};
703
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800704static __initdata struct params xen_fdt_params[] = {
705 UEFI_PARAM("System Table", "xen,uefi-system-table", system_table),
706 UEFI_PARAM("MemMap Address", "xen,uefi-mmap-start", mmap),
707 UEFI_PARAM("MemMap Size", "xen,uefi-mmap-size", mmap_size),
708 UEFI_PARAM("MemMap Desc. Size", "xen,uefi-mmap-desc-size", desc_size),
709 UEFI_PARAM("MemMap Desc. Version", "xen,uefi-mmap-desc-ver", desc_ver)
710};
711
712#define EFI_FDT_PARAMS_SIZE ARRAY_SIZE(fdt_params)
713
714static __initdata struct {
715 const char *uname;
716 const char *subnode;
717 struct params *params;
718} dt_params[] = {
719 { "hypervisor", "uefi", xen_fdt_params },
720 { "chosen", NULL, fdt_params },
721};
722
Mark Salter0302f712013-12-30 12:12:12 -0500723struct param_info {
Catalin Marinas29e24352014-07-08 16:54:18 +0100724 int found;
Mark Salter0302f712013-12-30 12:12:12 -0500725 void *params;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800726 const char *missing;
Mark Salter0302f712013-12-30 12:12:12 -0500727};
728
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800729static int __init __find_uefi_params(unsigned long node,
730 struct param_info *info,
731 struct params *params)
Mark Salter0302f712013-12-30 12:12:12 -0500732{
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100733 const void *prop;
734 void *dest;
Mark Salter0302f712013-12-30 12:12:12 -0500735 u64 val;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100736 int i, len;
Mark Salter0302f712013-12-30 12:12:12 -0500737
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800738 for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) {
739 prop = of_get_flat_dt_prop(node, params[i].propname, &len);
740 if (!prop) {
741 info->missing = params[i].name;
Mark Salter0302f712013-12-30 12:12:12 -0500742 return 0;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800743 }
744
745 dest = info->params + params[i].offset;
Catalin Marinas29e24352014-07-08 16:54:18 +0100746 info->found++;
Mark Salter0302f712013-12-30 12:12:12 -0500747
748 val = of_read_number(prop, len / sizeof(u32));
749
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800750 if (params[i].size == sizeof(u32))
Mark Salter0302f712013-12-30 12:12:12 -0500751 *(u32 *)dest = val;
752 else
753 *(u64 *)dest = val;
754
Leif Lindholm7968c0e2015-08-26 14:24:58 +0100755 if (efi_enabled(EFI_DBG))
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800756 pr_info(" %s: 0x%0*llx\n", params[i].name,
757 params[i].size * 2, val);
Mark Salter0302f712013-12-30 12:12:12 -0500758 }
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800759
Mark Salter0302f712013-12-30 12:12:12 -0500760 return 1;
761}
762
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800763static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
764 int depth, void *data)
765{
766 struct param_info *info = data;
767 int i;
768
769 for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
770 const char *subnode = dt_params[i].subnode;
771
772 if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) {
773 info->missing = dt_params[i].params[0].name;
774 continue;
775 }
776
777 if (subnode) {
Andrzej Hajda4af9ed52016-08-30 12:41:37 +0200778 int err = of_get_flat_dt_subnode_by_name(node, subnode);
779
780 if (err < 0)
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800781 return 0;
Andrzej Hajda4af9ed52016-08-30 12:41:37 +0200782
783 node = err;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800784 }
785
786 return __find_uefi_params(node, info, dt_params[i].params);
787 }
788
789 return 0;
790}
791
Leif Lindholm7968c0e2015-08-26 14:24:58 +0100792int __init efi_get_fdt_params(struct efi_fdt_params *params)
Mark Salter0302f712013-12-30 12:12:12 -0500793{
794 struct param_info info;
Catalin Marinas29e24352014-07-08 16:54:18 +0100795 int ret;
796
797 pr_info("Getting EFI parameters from FDT:\n");
Mark Salter0302f712013-12-30 12:12:12 -0500798
Catalin Marinas29e24352014-07-08 16:54:18 +0100799 info.found = 0;
Mark Salter0302f712013-12-30 12:12:12 -0500800 info.params = params;
801
Catalin Marinas29e24352014-07-08 16:54:18 +0100802 ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
803 if (!info.found)
804 pr_info("UEFI not found.\n");
805 else if (!ret)
806 pr_err("Can't find '%s' in device tree!\n",
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800807 info.missing);
Catalin Marinas29e24352014-07-08 16:54:18 +0100808
809 return ret;
Mark Salter0302f712013-12-30 12:12:12 -0500810}
811#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200812
813static __initdata char memory_type_name[][20] = {
814 "Reserved",
815 "Loader Code",
816 "Loader Data",
817 "Boot Code",
818 "Boot Data",
819 "Runtime Code",
820 "Runtime Data",
821 "Conventional Memory",
822 "Unusable Memory",
823 "ACPI Reclaim Memory",
824 "ACPI Memory NVS",
825 "Memory Mapped I/O",
826 "MMIO Port Space",
Robert Elliott35575e02016-02-01 22:07:07 +0000827 "PAL Code",
828 "Persistent Memory",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200829};
830
831char * __init efi_md_typeattr_format(char *buf, size_t size,
832 const efi_memory_desc_t *md)
833{
834 char *pos;
835 int type_len;
836 u64 attr;
837
838 pos = buf;
839 if (md->type >= ARRAY_SIZE(memory_type_name))
840 type_len = snprintf(pos, size, "[type=%u", md->type);
841 else
842 type_len = snprintf(pos, size, "[%-*s",
843 (int)(sizeof(memory_type_name[0]) - 1),
844 memory_type_name[md->type]);
845 if (type_len >= size)
846 return buf;
847
848 pos += type_len;
849 size -= type_len;
850
851 attr = md->attribute;
852 if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
Ard Biesheuvel87db73ae2015-08-07 09:36:54 +0100853 EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
854 EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
Robert Elliottc016ca02016-02-01 22:07:06 +0000855 EFI_MEMORY_NV |
Taku Izumi8be44322015-08-27 02:11:19 +0900856 EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200857 snprintf(pos, size, "|attr=0x%016llx]",
858 (unsigned long long)attr);
859 else
Robert Elliottc016ca02016-02-01 22:07:06 +0000860 snprintf(pos, size,
861 "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200862 attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
Taku Izumi8be44322015-08-27 02:11:19 +0900863 attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
Robert Elliottc016ca02016-02-01 22:07:06 +0000864 attr & EFI_MEMORY_NV ? "NV" : "",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200865 attr & EFI_MEMORY_XP ? "XP" : "",
866 attr & EFI_MEMORY_RP ? "RP" : "",
867 attr & EFI_MEMORY_WP ? "WP" : "",
Ard Biesheuvel87db73ae2015-08-07 09:36:54 +0100868 attr & EFI_MEMORY_RO ? "RO" : "",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200869 attr & EFI_MEMORY_UCE ? "UCE" : "",
870 attr & EFI_MEMORY_WB ? "WB" : "",
871 attr & EFI_MEMORY_WT ? "WT" : "",
872 attr & EFI_MEMORY_WC ? "WC" : "",
873 attr & EFI_MEMORY_UC ? "UC" : "");
874 return buf;
875}
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100876
877/*
Jan Beulich23f05712017-08-25 16:50:18 +0100878 * IA64 has a funky EFI memory map that doesn't work the same way as
879 * other architectures.
880 */
881#ifndef CONFIG_IA64
882/*
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100883 * efi_mem_attributes - lookup memmap attributes for physical address
884 * @phys_addr: the physical address to lookup
885 *
886 * Search in the EFI memory map for the region covering
887 * @phys_addr. Returns the EFI memory attributes if the region
888 * was found in the memory map, 0 otherwise.
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100889 */
Jan Beulich23f05712017-08-25 16:50:18 +0100890u64 efi_mem_attributes(unsigned long phys_addr)
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100891{
892 efi_memory_desc_t *md;
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100893
894 if (!efi_enabled(EFI_MEMMAP))
895 return 0;
896
Matt Fleming78ce2482016-04-25 21:06:38 +0100897 for_each_efi_memory_desc(md) {
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100898 if ((md->phys_addr <= phys_addr) &&
899 (phys_addr < (md->phys_addr +
900 (md->num_pages << EFI_PAGE_SHIFT))))
901 return md->attribute;
902 }
903 return 0;
904}
Matt Fleming806b0352016-04-25 21:06:58 +0100905
Jan Beulich23f05712017-08-25 16:50:18 +0100906/*
907 * efi_mem_type - lookup memmap type for physical address
908 * @phys_addr: the physical address to lookup
909 *
910 * Search in the EFI memory map for the region covering @phys_addr.
911 * Returns the EFI memory type if the region was found in the memory
912 * map, EFI_RESERVED_TYPE (zero) otherwise.
913 */
914int efi_mem_type(unsigned long phys_addr)
915{
916 const efi_memory_desc_t *md;
917
918 if (!efi_enabled(EFI_MEMMAP))
919 return -ENOTSUPP;
920
921 for_each_efi_memory_desc(md) {
922 if ((md->phys_addr <= phys_addr) &&
923 (phys_addr < (md->phys_addr +
924 (md->num_pages << EFI_PAGE_SHIFT))))
925 return md->type;
926 }
927 return -EINVAL;
928}
929#endif
930
Matt Fleming806b0352016-04-25 21:06:58 +0100931int efi_status_to_err(efi_status_t status)
932{
933 int err;
934
935 switch (status) {
936 case EFI_SUCCESS:
937 err = 0;
938 break;
939 case EFI_INVALID_PARAMETER:
940 err = -EINVAL;
941 break;
942 case EFI_OUT_OF_RESOURCES:
943 err = -ENOSPC;
944 break;
945 case EFI_DEVICE_ERROR:
946 err = -EIO;
947 break;
948 case EFI_WRITE_PROTECTED:
949 err = -EROFS;
950 break;
951 case EFI_SECURITY_VIOLATION:
952 err = -EACCES;
953 break;
954 case EFI_NOT_FOUND:
955 err = -ENOENT;
956 break;
Ard Biesheuveldce48e32016-07-15 21:36:31 +0200957 case EFI_ABORTED:
958 err = -EINTR;
959 break;
Matt Fleming806b0352016-04-25 21:06:58 +0100960 default:
961 err = -EINVAL;
962 }
963
964 return err;
965}
Ard Biesheuvel63625982016-11-12 21:32:31 +0000966
Tom Lendackya19d66c2017-07-17 16:10:13 -0500967bool efi_is_table_address(unsigned long phys_addr)
968{
969 unsigned int i;
970
971 if (phys_addr == EFI_INVALID_TABLE_ADDR)
972 return false;
973
974 for (i = 0; i < ARRAY_SIZE(efi_tables); i++)
975 if (*(efi_tables[i]) == phys_addr)
976 return true;
977
978 return false;
979}
980
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700981static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
Ard Biesheuvel63eb3222018-11-14 09:55:44 -0800982static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700983
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100984static int __init efi_memreserve_map_root(void)
985{
986 if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR)
987 return -ENODEV;
988
989 efi_memreserve_root = memremap(efi.mem_reserve,
990 sizeof(*efi_memreserve_root),
991 MEMREMAP_WB);
992 if (WARN_ON_ONCE(!efi_memreserve_root))
993 return -ENOMEM;
994 return 0;
995}
996
997int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700998{
Ard Biesheuvel63eb3222018-11-14 09:55:44 -0800999 struct linux_efi_memreserve *rsv;
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001000 unsigned long prsv;
1001 int rc, index;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001002
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001003 if (efi_memreserve_root == (void *)ULONG_MAX)
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001004 return -ENODEV;
1005
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001006 if (!efi_memreserve_root) {
1007 rc = efi_memreserve_map_root();
1008 if (rc)
1009 return rc;
1010 }
1011
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001012 /* first try to find a slot in an existing linked list entry */
1013 for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
1014 rsv = __va(prsv);
1015 index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
1016 if (index < rsv->size) {
1017 rsv->entry[index].base = addr;
1018 rsv->entry[index].size = size;
1019
1020 return 0;
1021 }
1022 }
1023
1024 /* no slot found - allocate a new linked list entry */
1025 rsv = (struct linux_efi_memreserve *)__get_free_page(GFP_ATOMIC);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001026 if (!rsv)
1027 return -ENOMEM;
1028
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001029 rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE);
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +01001030 atomic_set(&rsv->count, 1);
1031 rsv->entry[0].base = addr;
1032 rsv->entry[0].size = size;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001033
1034 spin_lock(&efi_mem_reserve_persistent_lock);
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001035 rsv->next = efi_memreserve_root->next;
1036 efi_memreserve_root->next = __pa(rsv);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001037 spin_unlock(&efi_mem_reserve_persistent_lock);
1038
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001039 return 0;
1040}
1041
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001042static int __init efi_memreserve_root_init(void)
1043{
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001044 if (efi_memreserve_root)
1045 return 0;
1046 if (efi_memreserve_map_root())
1047 efi_memreserve_root = (void *)ULONG_MAX;
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001048 return 0;
1049}
1050early_initcall(efi_memreserve_root_init);
1051
Ard Biesheuvel63625982016-11-12 21:32:31 +00001052#ifdef CONFIG_KEXEC
1053static int update_efi_random_seed(struct notifier_block *nb,
1054 unsigned long code, void *unused)
1055{
1056 struct linux_efi_random_seed *seed;
1057 u32 size = 0;
1058
1059 if (!kexec_in_progress)
1060 return NOTIFY_DONE;
1061
1062 seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB);
1063 if (seed != NULL) {
Ard Biesheuvelc2ceb5f2017-08-25 16:50:16 +01001064 size = min(seed->size, EFI_RANDOM_SEED_SIZE);
Ard Biesheuvel63625982016-11-12 21:32:31 +00001065 memunmap(seed);
1066 } else {
1067 pr_err("Could not map UEFI random seed!\n");
1068 }
1069 if (size > 0) {
1070 seed = memremap(efi.rng_seed, sizeof(*seed) + size,
1071 MEMREMAP_WB);
1072 if (seed != NULL) {
1073 seed->size = size;
1074 get_random_bytes(seed->bits, seed->size);
1075 memunmap(seed);
1076 } else {
1077 pr_err("Could not map UEFI random seed!\n");
1078 }
1079 }
1080 return NOTIFY_DONE;
1081}
1082
1083static struct notifier_block efi_random_seed_nb = {
1084 .notifier_call = update_efi_random_seed,
1085};
1086
1087static int register_update_efi_random_seed(void)
1088{
1089 if (efi.rng_seed == EFI_INVALID_TABLE_ADDR)
1090 return 0;
1091 return register_reboot_notifier(&efi_random_seed_nb);
1092}
1093late_initcall(register_update_efi_random_seed);
1094#endif