blob: 21ea99f651134be47161831266f00cb43fb85f56 [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>
Matthew Garrett1957a85b2019-08-19 17:18:04 -070033#include <linux/security.h>
Leif Lindholm272686b2013-09-05 11:34:54 +010034
Ard Biesheuvel0f7f2f02016-01-12 14:22:46 +010035#include <asm/early_ioremap.h>
Ard Biesheuvelf7d92482015-11-30 13:28:19 +010036
Leif Lindholm272686b2013-09-05 11:34:54 +010037struct efi __read_mostly efi = {
Ard Biesheuvelbf924862015-09-09 10:08:15 +020038 .mps = EFI_INVALID_TABLE_ADDR,
39 .acpi = EFI_INVALID_TABLE_ADDR,
40 .acpi20 = EFI_INVALID_TABLE_ADDR,
41 .smbios = EFI_INVALID_TABLE_ADDR,
42 .smbios3 = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvelbf924862015-09-09 10:08:15 +020043 .boot_info = EFI_INVALID_TABLE_ADDR,
44 .hcdp = EFI_INVALID_TABLE_ADDR,
45 .uga = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvelbf924862015-09-09 10:08:15 +020046 .fw_vendor = EFI_INVALID_TABLE_ADDR,
47 .runtime = EFI_INVALID_TABLE_ADDR,
48 .config_table = EFI_INVALID_TABLE_ADDR,
49 .esrt = EFI_INVALID_TABLE_ADDR,
50 .properties_table = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvela604af02016-04-25 21:06:44 +010051 .mem_attr_table = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvel63625982016-11-12 21:32:31 +000052 .rng_seed = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvel71e09402018-09-21 09:32:44 -070053 .tpm_log = EFI_INVALID_TABLE_ADDR,
Matthew Garrettc46f3402019-05-20 13:54:59 -070054 .tpm_final_log = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvel71e09402018-09-21 09:32:44 -070055 .mem_reserve = EFI_INVALID_TABLE_ADDR,
Leif Lindholm272686b2013-09-05 11:34:54 +010056};
57EXPORT_SYMBOL(efi);
Tom Gundersena9499fa2013-02-08 15:37:06 +000058
Sai Praneeth7e904a92018-03-12 08:44:56 +000059struct mm_struct efi_mm = {
60 .mm_rb = RB_ROOT,
61 .mm_users = ATOMIC_INIT(2),
62 .mm_count = ATOMIC_INIT(1),
63 .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
64 .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
65 .mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
Rik van Rielc1a2f7f2018-07-16 15:03:31 -040066 .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0},
Sai Praneeth7e904a92018-03-12 08:44:56 +000067};
68
Sai Praneeth3eb420e2018-07-11 11:40:35 +020069struct workqueue_struct *efi_rts_wq;
70
Dave Youngb2e0a542014-08-14 17:15:26 +080071static bool disable_runtime;
72static int __init setup_noefi(char *arg)
73{
74 disable_runtime = true;
75 return 0;
76}
77early_param("noefi", setup_noefi);
78
79bool efi_runtime_disabled(void)
80{
81 return disable_runtime;
82}
83
Dan Williamsb617c522019-11-06 17:43:11 -080084bool __pure __efi_soft_reserve_enabled(void)
85{
86 return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE);
87}
88
Dave Young5ae36832014-08-14 17:15:28 +080089static int __init parse_efi_cmdline(char *str)
90{
Ricardo Neri9115c752015-07-15 19:36:03 -070091 if (!str) {
92 pr_warn("need at least one option\n");
93 return -EINVAL;
94 }
95
Leif Lindholm12dd00e2015-08-26 14:24:56 +010096 if (parse_option_str(str, "debug"))
97 set_bit(EFI_DBG, &efi.flags);
98
Dave Young5ae36832014-08-14 17:15:28 +080099 if (parse_option_str(str, "noruntime"))
100 disable_runtime = true;
101
Dan Williamsb617c522019-11-06 17:43:11 -0800102 if (parse_option_str(str, "nosoftreserve"))
103 set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
104
Dave Young5ae36832014-08-14 17:15:28 +0800105 return 0;
106}
107early_param("efi", parse_efi_cmdline);
108
Peter Jones0bb54902015-04-28 18:44:31 -0400109struct kobject *efi_kobj;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000110
111/*
112 * Let's not leave out systab information that snuck into
113 * the efivars driver
Dave Young0b02e442017-12-06 09:50:10 +0000114 * Note, do not add more fields in systab sysfs file as it breaks sysfs
115 * one value per file rule!
Tom Gundersena9499fa2013-02-08 15:37:06 +0000116 */
117static ssize_t systab_show(struct kobject *kobj,
118 struct kobj_attribute *attr, char *buf)
119{
120 char *str = buf;
121
122 if (!kobj || !buf)
123 return -EINVAL;
124
125 if (efi.mps != EFI_INVALID_TABLE_ADDR)
126 str += sprintf(str, "MPS=0x%lx\n", efi.mps);
127 if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
128 str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
129 if (efi.acpi != EFI_INVALID_TABLE_ADDR)
130 str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
Jean Delvareb119fe02015-04-30 15:23:05 +0200131 /*
132 * If both SMBIOS and SMBIOS3 entry points are implemented, the
133 * SMBIOS3 entry point shall be preferred, so we list it first to
134 * let applications stop parsing after the first match.
135 */
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200136 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
137 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
Jean Delvareb119fe02015-04-30 15:23:05 +0200138 if (efi.smbios != EFI_INVALID_TABLE_ADDR)
139 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
Tom Gundersena9499fa2013-02-08 15:37:06 +0000140 if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
141 str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
142 if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
143 str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
144 if (efi.uga != EFI_INVALID_TABLE_ADDR)
145 str += sprintf(str, "UGA=0x%lx\n", efi.uga);
146
147 return str - buf;
148}
149
Greg Kroah-Hartmanaf97a772017-12-06 09:50:08 +0000150static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
Tom Gundersena9499fa2013-02-08 15:37:06 +0000151
Dave Younga0998eb2013-12-20 18:02:17 +0800152#define EFI_FIELD(var) efi.var
153
154#define EFI_ATTR_SHOW(name) \
155static ssize_t name##_show(struct kobject *kobj, \
156 struct kobj_attribute *attr, char *buf) \
157{ \
158 return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
159}
160
161EFI_ATTR_SHOW(fw_vendor);
162EFI_ATTR_SHOW(runtime);
163EFI_ATTR_SHOW(config_table);
164
Steve McIntyre2859dff2015-01-09 15:29:53 +0000165static ssize_t fw_platform_size_show(struct kobject *kobj,
166 struct kobj_attribute *attr, char *buf)
167{
168 return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
169}
170
Dave Younga0998eb2013-12-20 18:02:17 +0800171static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
172static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
173static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
Steve McIntyre2859dff2015-01-09 15:29:53 +0000174static struct kobj_attribute efi_attr_fw_platform_size =
175 __ATTR_RO(fw_platform_size);
Dave Younga0998eb2013-12-20 18:02:17 +0800176
Tom Gundersena9499fa2013-02-08 15:37:06 +0000177static struct attribute *efi_subsys_attrs[] = {
178 &efi_attr_systab.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800179 &efi_attr_fw_vendor.attr,
180 &efi_attr_runtime.attr,
181 &efi_attr_config_table.attr,
Steve McIntyre2859dff2015-01-09 15:29:53 +0000182 &efi_attr_fw_platform_size.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800183 NULL,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000184};
185
Dave Younga0998eb2013-12-20 18:02:17 +0800186static umode_t efi_attr_is_visible(struct kobject *kobj,
187 struct attribute *attr, int n)
188{
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200189 if (attr == &efi_attr_fw_vendor.attr) {
190 if (efi_enabled(EFI_PARAVIRT) ||
191 efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
192 return 0;
193 } else if (attr == &efi_attr_runtime.attr) {
194 if (efi.runtime == EFI_INVALID_TABLE_ADDR)
195 return 0;
196 } else if (attr == &efi_attr_config_table.attr) {
197 if (efi.config_table == EFI_INVALID_TABLE_ADDR)
198 return 0;
199 }
Dave Younga0998eb2013-12-20 18:02:17 +0800200
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200201 return attr->mode;
Dave Younga0998eb2013-12-20 18:02:17 +0800202}
203
Arvind Yadav3ad6bd72017-08-18 20:49:46 +0100204static const struct attribute_group efi_subsys_attr_group = {
Tom Gundersena9499fa2013-02-08 15:37:06 +0000205 .attrs = efi_subsys_attrs,
Dave Younga0998eb2013-12-20 18:02:17 +0800206 .is_visible = efi_attr_is_visible,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000207};
208
209static struct efivars generic_efivars;
210static struct efivar_operations generic_ops;
211
212static int generic_ops_register(void)
213{
214 generic_ops.get_variable = efi.get_variable;
215 generic_ops.set_variable = efi.set_variable;
Ard Biesheuvel9c6672a2016-02-01 22:06:55 +0000216 generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000217 generic_ops.get_next_variable = efi.get_next_variable;
Matt Fleminga614e192013-04-30 11:30:24 +0100218 generic_ops.query_variable_store = efi_query_variable_store;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000219
220 return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
221}
222
223static void generic_ops_unregister(void)
224{
225 efivars_unregister(&generic_efivars);
226}
227
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300228#if IS_ENABLED(CONFIG_ACPI)
229#define EFIVAR_SSDT_NAME_MAX 16
230static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
231static int __init efivar_ssdt_setup(char *str)
232{
Matthew Garrett1957a85b2019-08-19 17:18:04 -0700233 int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
234
235 if (ret)
236 return ret;
237
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300238 if (strlen(str) < sizeof(efivar_ssdt))
239 memcpy(efivar_ssdt, str, strlen(str));
240 else
241 pr_warn("efivar_ssdt: name too long: %s\n", str);
242 return 0;
243}
244__setup("efivar_ssdt=", efivar_ssdt_setup);
245
246static __init int efivar_ssdt_iter(efi_char16_t *name, efi_guid_t vendor,
247 unsigned long name_size, void *data)
248{
249 struct efivar_entry *entry;
250 struct list_head *list = data;
251 char utf8_name[EFIVAR_SSDT_NAME_MAX];
252 int limit = min_t(unsigned long, EFIVAR_SSDT_NAME_MAX, name_size);
253
254 ucs2_as_utf8(utf8_name, name, limit - 1);
255 if (strncmp(utf8_name, efivar_ssdt, limit) != 0)
256 return 0;
257
258 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
259 if (!entry)
260 return 0;
261
262 memcpy(entry->var.VariableName, name, name_size);
263 memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t));
264
265 efivar_entry_add(entry, list);
266
267 return 0;
268}
269
270static __init int efivar_ssdt_load(void)
271{
272 LIST_HEAD(entries);
273 struct efivar_entry *entry, *aux;
274 unsigned long size;
275 void *data;
276 int ret;
277
Ard Biesheuvelc05f8f92019-10-02 18:58:59 +0200278 if (!efivar_ssdt[0])
279 return 0;
280
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300281 ret = efivar_init(efivar_ssdt_iter, &entries, true, &entries);
282
283 list_for_each_entry_safe(entry, aux, &entries, list) {
284 pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt,
285 &entry->var.VendorGuid);
286
287 list_del(&entry->list);
288
289 ret = efivar_entry_size(entry, &size);
290 if (ret) {
291 pr_err("failed to get var size\n");
292 goto free_entry;
293 }
294
295 data = kmalloc(size, GFP_KERNEL);
Dan Carpentera75dcb52016-10-18 15:33:18 +0100296 if (!data) {
297 ret = -ENOMEM;
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300298 goto free_entry;
Dan Carpentera75dcb52016-10-18 15:33:18 +0100299 }
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300300
301 ret = efivar_entry_get(entry, NULL, &size, data);
302 if (ret) {
303 pr_err("failed to get var data\n");
304 goto free_data;
305 }
306
Nikolaus Voss17700932019-10-25 14:36:53 -0700307 ret = acpi_load_table(data, NULL);
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300308 if (ret) {
309 pr_err("failed to load table: %d\n", ret);
310 goto free_data;
311 }
312
313 goto free_entry;
314
315free_data:
316 kfree(data);
317
318free_entry:
319 kfree(entry);
320 }
321
322 return ret;
323}
324#else
325static inline int efivar_ssdt_load(void) { return 0; }
326#endif
327
Tom Gundersena9499fa2013-02-08 15:37:06 +0000328/*
329 * We register the efi subsystem with the firmware subsystem and the
330 * efivars subsystem with the efi subsystem, if the system was booted with
331 * EFI.
332 */
333static int __init efisubsys_init(void)
334{
335 int error;
336
337 if (!efi_enabled(EFI_BOOT))
338 return 0;
339
Sai Praneeth3eb420e2018-07-11 11:40:35 +0200340 /*
341 * Since we process only one efi_runtime_service() at a time, an
342 * ordered workqueue (which creates only one execution context)
343 * should suffice all our needs.
344 */
345 efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
346 if (!efi_rts_wq) {
347 pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
348 clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
349 return 0;
350 }
351
Tom Gundersena9499fa2013-02-08 15:37:06 +0000352 /* We register the efi directory at /sys/firmware/efi */
353 efi_kobj = kobject_create_and_add("efi", firmware_kobj);
354 if (!efi_kobj) {
355 pr_err("efi: Firmware registration failed.\n");
356 return -ENOMEM;
357 }
358
359 error = generic_ops_register();
360 if (error)
361 goto err_put;
362
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300363 if (efi_enabled(EFI_RUNTIME_SERVICES))
364 efivar_ssdt_load();
365
Tom Gundersena9499fa2013-02-08 15:37:06 +0000366 error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
367 if (error) {
368 pr_err("efi: Sysfs attribute export failed with error %d.\n",
369 error);
370 goto err_unregister;
371 }
372
Dave Young926172d2013-12-20 18:02:18 +0800373 error = efi_runtime_map_init(efi_kobj);
374 if (error)
375 goto err_remove_group;
376
Tom Gundersena9499fa2013-02-08 15:37:06 +0000377 /* and the standard mountpoint for efivarfs */
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -0500378 error = sysfs_create_mount_point(efi_kobj, "efivars");
379 if (error) {
Tom Gundersena9499fa2013-02-08 15:37:06 +0000380 pr_err("efivars: Subsystem registration failed.\n");
Tom Gundersena9499fa2013-02-08 15:37:06 +0000381 goto err_remove_group;
382 }
383
384 return 0;
385
386err_remove_group:
387 sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
388err_unregister:
389 generic_ops_unregister();
390err_put:
391 kobject_put(efi_kobj);
392 return error;
393}
394
395subsys_initcall(efisubsys_init);
Leif Lindholm272686b2013-09-05 11:34:54 +0100396
Peter Jones0bb54902015-04-28 18:44:31 -0400397/*
398 * Find the efi memory descriptor for a given physical address. Given a
Matt Flemingdca0f972016-02-27 15:52:50 +0000399 * physical address, determine if it exists within an EFI Memory Map entry,
Peter Jones0bb54902015-04-28 18:44:31 -0400400 * and if so, populate the supplied memory descriptor with the appropriate
401 * data.
402 */
Ard Biesheuvel7e1550b2018-07-11 11:40:39 +0200403int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
Peter Jones0bb54902015-04-28 18:44:31 -0400404{
Matt Flemingdca0f972016-02-27 15:52:50 +0000405 efi_memory_desc_t *md;
Peter Jones0bb54902015-04-28 18:44:31 -0400406
407 if (!efi_enabled(EFI_MEMMAP)) {
408 pr_err_once("EFI_MEMMAP is not enabled.\n");
409 return -EINVAL;
410 }
411
Peter Jones0bb54902015-04-28 18:44:31 -0400412 if (!out_md) {
413 pr_err_once("out_md is null.\n");
414 return -EINVAL;
415 }
Peter Jones0bb54902015-04-28 18:44:31 -0400416
Matt Flemingdca0f972016-02-27 15:52:50 +0000417 for_each_efi_memory_desc(md) {
Peter Jones0bb54902015-04-28 18:44:31 -0400418 u64 size;
419 u64 end;
420
Peter Jones0bb54902015-04-28 18:44:31 -0400421 size = md->num_pages << EFI_PAGE_SHIFT;
422 end = md->phys_addr + size;
423 if (phys_addr >= md->phys_addr && phys_addr < end) {
424 memcpy(out_md, md, sizeof(*out_md));
Peter Jones0bb54902015-04-28 18:44:31 -0400425 return 0;
426 }
Peter Jones0bb54902015-04-28 18:44:31 -0400427 }
Peter Jones0bb54902015-04-28 18:44:31 -0400428 return -ENOENT;
429}
430
431/*
432 * Calculate the highest address of an efi memory descriptor.
433 */
434u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
435{
436 u64 size = md->num_pages << EFI_PAGE_SHIFT;
437 u64 end = md->phys_addr + size;
438 return end;
439}
Leif Lindholm272686b2013-09-05 11:34:54 +0100440
Matt Fleming816e7612016-02-29 21:22:52 +0000441void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {}
442
443/**
444 * efi_mem_reserve - Reserve an EFI memory region
445 * @addr: Physical address to reserve
446 * @size: Size of reservation
447 *
448 * Mark a region as reserved from general kernel allocation and
449 * prevent it being released by efi_free_boot_services().
450 *
451 * This function should be called drivers once they've parsed EFI
452 * configuration tables to figure out where their data lives, e.g.
453 * efi_esrt_init().
454 */
455void __init efi_mem_reserve(phys_addr_t addr, u64 size)
456{
457 if (!memblock_is_region_reserved(addr, size))
458 memblock_reserve(addr, size);
459
460 /*
461 * Some architectures (x86) reserve all boot services ranges
462 * until efi_free_boot_services() because of buggy firmware
463 * implementations. This means the above memblock_reserve() is
464 * superfluous on x86 and instead what it needs to do is
465 * ensure the @start, @size is not freed.
466 */
467 efi_arch_mem_reserve(addr, size);
468}
469
Leif Lindholm272686b2013-09-05 11:34:54 +0100470static __initdata efi_config_table_type_t common_tables[] = {
471 {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
472 {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
473 {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
474 {MPS_TABLE_GUID, "MPS", &efi.mps},
Leif Lindholm272686b2013-09-05 11:34:54 +0100475 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200476 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
Leif Lindholm272686b2013-09-05 11:34:54 +0100477 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
Peter Jones0bb54902015-04-28 18:44:31 -0400478 {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
Ard Biesheuvelbf924862015-09-09 10:08:15 +0200479 {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
Ard Biesheuvela604af02016-04-25 21:06:44 +0100480 {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
Ard Biesheuvel63625982016-11-12 21:32:31 +0000481 {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
Thiebaud Weksteen33b6d032017-09-20 10:13:39 +0200482 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
Matthew Garrettc46f3402019-05-20 13:54:59 -0700483 {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700484 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
Narendra K1c5fecb2019-07-10 18:59:15 +0000485#ifdef CONFIG_EFI_RCI2_TABLE
486 {DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys},
487#endif
Daeseok Youn69e60842014-02-13 17:16:36 +0900488 {NULL_GUID, NULL, NULL},
Leif Lindholm272686b2013-09-05 11:34:54 +0100489};
490
491static __init int match_config_table(efi_guid_t *guid,
492 unsigned long table,
493 efi_config_table_type_t *table_types)
494{
Leif Lindholm272686b2013-09-05 11:34:54 +0100495 int i;
496
497 if (table_types) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100498 for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100499 if (!efi_guidcmp(*guid, table_types[i].guid)) {
500 *(table_types[i].ptr) = table;
Ard Biesheuvel801820b2016-04-25 21:06:53 +0100501 if (table_types[i].name)
502 pr_cont(" %s=0x%lx ",
503 table_types[i].name, table);
Leif Lindholm272686b2013-09-05 11:34:54 +0100504 return 1;
505 }
506 }
507 }
508
509 return 0;
510}
511
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200512int __init efi_config_parse_tables(void *config_tables, int count, int sz,
513 efi_config_table_type_t *arch_tables)
514{
515 void *tablep;
516 int i;
517
518 tablep = config_tables;
519 pr_info("");
520 for (i = 0; i < count; i++) {
521 efi_guid_t guid;
522 unsigned long table;
523
524 if (efi_enabled(EFI_64BIT)) {
525 u64 table64;
526 guid = ((efi_config_table_64_t *)tablep)->guid;
527 table64 = ((efi_config_table_64_t *)tablep)->table;
528 table = table64;
529#ifndef CONFIG_64BIT
530 if (table64 >> 32) {
531 pr_cont("\n");
532 pr_err("Table located above 4GB, disabling EFI.\n");
533 return -EINVAL;
534 }
535#endif
536 } else {
537 guid = ((efi_config_table_32_t *)tablep)->guid;
538 table = ((efi_config_table_32_t *)tablep)->table;
539 }
540
541 if (!match_config_table(&guid, table, common_tables))
542 match_config_table(&guid, table, arch_tables);
543
544 tablep += sz;
545 }
546 pr_cont("\n");
547 set_bit(EFI_CONFIG_TABLES, &efi.flags);
Ard Biesheuvela1041712015-09-23 07:29:34 -0700548
Ard Biesheuvel63625982016-11-12 21:32:31 +0000549 if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
550 struct linux_efi_random_seed *seed;
551 u32 size = 0;
552
553 seed = early_memremap(efi.rng_seed, sizeof(*seed));
554 if (seed != NULL) {
Jason A. Donenfeldbe36f9e2020-02-21 09:48:49 +0100555 size = READ_ONCE(seed->size);
Ard Biesheuvel63625982016-11-12 21:32:31 +0000556 early_memunmap(seed, sizeof(*seed));
557 } else {
558 pr_err("Could not map UEFI random seed!\n");
559 }
560 if (size > 0) {
561 seed = early_memremap(efi.rng_seed,
562 sizeof(*seed) + size);
563 if (seed != NULL) {
Ard Biesheuvel5b4e4c32018-03-08 08:00:18 +0000564 pr_notice("seeding entropy pool\n");
Jason A. Donenfeldbe36f9e2020-02-21 09:48:49 +0100565 add_bootloader_randomness(seed->bits, size);
Ard Biesheuvel63625982016-11-12 21:32:31 +0000566 early_memunmap(seed, sizeof(*seed) + size);
567 } else {
568 pr_err("Could not map UEFI random seed!\n");
569 }
570 }
571 }
572
Daniel Kiper457ea3f2017-06-22 12:51:36 +0200573 if (efi_enabled(EFI_MEMMAP))
574 efi_memattr_init();
Sai Praneeth3a6b6c62017-01-31 13:21:35 +0000575
Thiebaud Weksteen33b6d032017-09-20 10:13:39 +0200576 efi_tpm_eventlog_init();
577
Ard Biesheuvela1041712015-09-23 07:29:34 -0700578 /* Parse the EFI Properties table if it exists */
579 if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
580 efi_properties_table_t *tbl;
581
582 tbl = early_memremap(efi.properties_table, sizeof(*tbl));
583 if (tbl == NULL) {
584 pr_err("Could not map Properties table!\n");
585 return -ENOMEM;
586 }
587
588 if (tbl->memory_protection_attribute &
589 EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
590 set_bit(EFI_NX_PE_DATA, &efi.flags);
591
592 early_memunmap(tbl, sizeof(*tbl));
593 }
594
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700595 if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) {
596 unsigned long prsv = efi.mem_reserve;
597
598 while (prsv) {
599 struct linux_efi_memreserve *rsv;
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100600 u8 *p;
601 int i;
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700602
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100603 /*
604 * Just map a full page: that is what we will get
605 * anyway, and it permits us to map the entire entry
606 * before knowing its size.
607 */
608 p = early_memremap(ALIGN_DOWN(prsv, PAGE_SIZE),
609 PAGE_SIZE);
610 if (p == NULL) {
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700611 pr_err("Could not map UEFI memreserve entry!\n");
612 return -ENOMEM;
613 }
614
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100615 rsv = (void *)(p + prsv % PAGE_SIZE);
616
617 /* reserve the entry itself */
618 memblock_reserve(prsv, EFI_MEMRESERVE_SIZE(rsv->size));
619
620 for (i = 0; i < atomic_read(&rsv->count); i++) {
621 memblock_reserve(rsv->entry[i].base,
622 rsv->entry[i].size);
623 }
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700624
625 prsv = rsv->next;
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100626 early_memunmap(p, PAGE_SIZE);
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700627 }
628 }
629
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200630 return 0;
631}
632
Leif Lindholm272686b2013-09-05 11:34:54 +0100633int __init efi_config_init(efi_config_table_type_t *arch_tables)
634{
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200635 void *config_tables;
636 int sz, ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100637
Rob Bradford88447c52019-05-25 13:25:59 +0200638 if (efi.systab->nr_tables == 0)
639 return 0;
640
Leif Lindholm272686b2013-09-05 11:34:54 +0100641 if (efi_enabled(EFI_64BIT))
642 sz = sizeof(efi_config_table_64_t);
643 else
644 sz = sizeof(efi_config_table_32_t);
645
646 /*
647 * Let's see what config tables the firmware passed to us.
648 */
649 config_tables = early_memremap(efi.systab->tables,
650 efi.systab->nr_tables * sz);
651 if (config_tables == NULL) {
652 pr_err("Could not map Configuration table!\n");
653 return -ENOMEM;
654 }
655
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200656 ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
657 arch_tables);
Leif Lindholm272686b2013-09-05 11:34:54 +0100658
Daniel Kiperabc93f82014-06-30 19:52:56 +0200659 early_memunmap(config_tables, efi.systab->nr_tables * sz);
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200660 return ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100661}
Mark Salter0302f712013-12-30 12:12:12 -0500662
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800663#ifdef CONFIG_EFI_VARS_MODULE
664static int __init efi_load_efivars(void)
665{
666 struct platform_device *pdev;
667
668 if (!efi_enabled(EFI_RUNTIME_SERVICES))
669 return 0;
670
671 pdev = platform_device_register_simple("efivars", 0, NULL, 0);
Vasyl Gomonovych50342b22018-01-02 18:10:40 +0000672 return PTR_ERR_OR_ZERO(pdev);
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800673}
674device_initcall(efi_load_efivars);
675#endif
676
Mark Salter0302f712013-12-30 12:12:12 -0500677#ifdef CONFIG_EFI_PARAMS_FROM_FDT
678
679#define UEFI_PARAM(name, prop, field) \
680 { \
681 { name }, \
682 { prop }, \
683 offsetof(struct efi_fdt_params, field), \
Pankaj Bharadiyac5936422019-12-09 10:31:43 -0800684 sizeof_field(struct efi_fdt_params, field) \
Mark Salter0302f712013-12-30 12:12:12 -0500685 }
686
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800687struct params {
Mark Salter0302f712013-12-30 12:12:12 -0500688 const char name[32];
689 const char propname[32];
690 int offset;
691 int size;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800692};
693
694static __initdata struct params fdt_params[] = {
Mark Salter0302f712013-12-30 12:12:12 -0500695 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
696 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
697 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
698 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
699 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
700};
701
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800702static __initdata struct params xen_fdt_params[] = {
703 UEFI_PARAM("System Table", "xen,uefi-system-table", system_table),
704 UEFI_PARAM("MemMap Address", "xen,uefi-mmap-start", mmap),
705 UEFI_PARAM("MemMap Size", "xen,uefi-mmap-size", mmap_size),
706 UEFI_PARAM("MemMap Desc. Size", "xen,uefi-mmap-desc-size", desc_size),
707 UEFI_PARAM("MemMap Desc. Version", "xen,uefi-mmap-desc-ver", desc_ver)
708};
709
710#define EFI_FDT_PARAMS_SIZE ARRAY_SIZE(fdt_params)
711
712static __initdata struct {
713 const char *uname;
714 const char *subnode;
715 struct params *params;
716} dt_params[] = {
717 { "hypervisor", "uefi", xen_fdt_params },
718 { "chosen", NULL, fdt_params },
719};
720
Mark Salter0302f712013-12-30 12:12:12 -0500721struct param_info {
Catalin Marinas29e24352014-07-08 16:54:18 +0100722 int found;
Mark Salter0302f712013-12-30 12:12:12 -0500723 void *params;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800724 const char *missing;
Mark Salter0302f712013-12-30 12:12:12 -0500725};
726
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800727static int __init __find_uefi_params(unsigned long node,
728 struct param_info *info,
729 struct params *params)
Mark Salter0302f712013-12-30 12:12:12 -0500730{
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100731 const void *prop;
732 void *dest;
Mark Salter0302f712013-12-30 12:12:12 -0500733 u64 val;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100734 int i, len;
Mark Salter0302f712013-12-30 12:12:12 -0500735
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800736 for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) {
737 prop = of_get_flat_dt_prop(node, params[i].propname, &len);
738 if (!prop) {
739 info->missing = params[i].name;
Mark Salter0302f712013-12-30 12:12:12 -0500740 return 0;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800741 }
742
743 dest = info->params + params[i].offset;
Catalin Marinas29e24352014-07-08 16:54:18 +0100744 info->found++;
Mark Salter0302f712013-12-30 12:12:12 -0500745
746 val = of_read_number(prop, len / sizeof(u32));
747
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800748 if (params[i].size == sizeof(u32))
Mark Salter0302f712013-12-30 12:12:12 -0500749 *(u32 *)dest = val;
750 else
751 *(u64 *)dest = val;
752
Leif Lindholm7968c0e2015-08-26 14:24:58 +0100753 if (efi_enabled(EFI_DBG))
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800754 pr_info(" %s: 0x%0*llx\n", params[i].name,
755 params[i].size * 2, val);
Mark Salter0302f712013-12-30 12:12:12 -0500756 }
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800757
Mark Salter0302f712013-12-30 12:12:12 -0500758 return 1;
759}
760
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800761static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
762 int depth, void *data)
763{
764 struct param_info *info = data;
765 int i;
766
767 for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
768 const char *subnode = dt_params[i].subnode;
769
770 if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) {
771 info->missing = dt_params[i].params[0].name;
772 continue;
773 }
774
775 if (subnode) {
Andrzej Hajda4af9ed52016-08-30 12:41:37 +0200776 int err = of_get_flat_dt_subnode_by_name(node, subnode);
777
778 if (err < 0)
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800779 return 0;
Andrzej Hajda4af9ed52016-08-30 12:41:37 +0200780
781 node = err;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800782 }
783
784 return __find_uefi_params(node, info, dt_params[i].params);
785 }
786
787 return 0;
788}
789
Leif Lindholm7968c0e2015-08-26 14:24:58 +0100790int __init efi_get_fdt_params(struct efi_fdt_params *params)
Mark Salter0302f712013-12-30 12:12:12 -0500791{
792 struct param_info info;
Catalin Marinas29e24352014-07-08 16:54:18 +0100793 int ret;
794
795 pr_info("Getting EFI parameters from FDT:\n");
Mark Salter0302f712013-12-30 12:12:12 -0500796
Catalin Marinas29e24352014-07-08 16:54:18 +0100797 info.found = 0;
Mark Salter0302f712013-12-30 12:12:12 -0500798 info.params = params;
799
Catalin Marinas29e24352014-07-08 16:54:18 +0100800 ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
801 if (!info.found)
802 pr_info("UEFI not found.\n");
803 else if (!ret)
804 pr_err("Can't find '%s' in device tree!\n",
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800805 info.missing);
Catalin Marinas29e24352014-07-08 16:54:18 +0100806
807 return ret;
Mark Salter0302f712013-12-30 12:12:12 -0500808}
809#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200810
811static __initdata char memory_type_name[][20] = {
812 "Reserved",
813 "Loader Code",
814 "Loader Data",
815 "Boot Code",
816 "Boot Data",
817 "Runtime Code",
818 "Runtime Data",
819 "Conventional Memory",
820 "Unusable Memory",
821 "ACPI Reclaim Memory",
822 "ACPI Memory NVS",
823 "Memory Mapped I/O",
824 "MMIO Port Space",
Robert Elliott35575e02016-02-01 22:07:07 +0000825 "PAL Code",
826 "Persistent Memory",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200827};
828
829char * __init efi_md_typeattr_format(char *buf, size_t size,
830 const efi_memory_desc_t *md)
831{
832 char *pos;
833 int type_len;
834 u64 attr;
835
836 pos = buf;
837 if (md->type >= ARRAY_SIZE(memory_type_name))
838 type_len = snprintf(pos, size, "[type=%u", md->type);
839 else
840 type_len = snprintf(pos, size, "[%-*s",
841 (int)(sizeof(memory_type_name[0]) - 1),
842 memory_type_name[md->type]);
843 if (type_len >= size)
844 return buf;
845
846 pos += type_len;
847 size -= type_len;
848
849 attr = md->attribute;
850 if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
Ard Biesheuvel87db73ae2015-08-07 09:36:54 +0100851 EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
852 EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
Dan Williamsfe3e5e62019-11-06 17:43:00 -0800853 EFI_MEMORY_NV | EFI_MEMORY_SP |
Taku Izumi8be44322015-08-27 02:11:19 +0900854 EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200855 snprintf(pos, size, "|attr=0x%016llx]",
856 (unsigned long long)attr);
857 else
Robert Elliottc016ca02016-02-01 22:07:06 +0000858 snprintf(pos, size,
Dan Williamsfe3e5e62019-11-06 17:43:00 -0800859 "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200860 attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
Taku Izumi8be44322015-08-27 02:11:19 +0900861 attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
Dan Williamsfe3e5e62019-11-06 17:43:00 -0800862 attr & EFI_MEMORY_SP ? "SP" : "",
Robert Elliottc016ca02016-02-01 22:07:06 +0000863 attr & EFI_MEMORY_NV ? "NV" : "",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200864 attr & EFI_MEMORY_XP ? "XP" : "",
865 attr & EFI_MEMORY_RP ? "RP" : "",
866 attr & EFI_MEMORY_WP ? "WP" : "",
Ard Biesheuvel87db73ae2015-08-07 09:36:54 +0100867 attr & EFI_MEMORY_RO ? "RO" : "",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200868 attr & EFI_MEMORY_UCE ? "UCE" : "",
869 attr & EFI_MEMORY_WB ? "WB" : "",
870 attr & EFI_MEMORY_WT ? "WT" : "",
871 attr & EFI_MEMORY_WC ? "WC" : "",
872 attr & EFI_MEMORY_UC ? "UC" : "");
873 return buf;
874}
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100875
876/*
Jan Beulich23f05712017-08-25 16:50:18 +0100877 * IA64 has a funky EFI memory map that doesn't work the same way as
878 * other architectures.
879 */
880#ifndef CONFIG_IA64
881/*
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100882 * efi_mem_attributes - lookup memmap attributes for physical address
883 * @phys_addr: the physical address to lookup
884 *
885 * Search in the EFI memory map for the region covering
886 * @phys_addr. Returns the EFI memory attributes if the region
887 * was found in the memory map, 0 otherwise.
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100888 */
Jan Beulich23f05712017-08-25 16:50:18 +0100889u64 efi_mem_attributes(unsigned long phys_addr)
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100890{
891 efi_memory_desc_t *md;
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100892
893 if (!efi_enabled(EFI_MEMMAP))
894 return 0;
895
Matt Fleming78ce2482016-04-25 21:06:38 +0100896 for_each_efi_memory_desc(md) {
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100897 if ((md->phys_addr <= phys_addr) &&
898 (phys_addr < (md->phys_addr +
899 (md->num_pages << EFI_PAGE_SHIFT))))
900 return md->attribute;
901 }
902 return 0;
903}
Matt Fleming806b0352016-04-25 21:06:58 +0100904
Jan Beulich23f05712017-08-25 16:50:18 +0100905/*
906 * efi_mem_type - lookup memmap type for physical address
907 * @phys_addr: the physical address to lookup
908 *
909 * Search in the EFI memory map for the region covering @phys_addr.
910 * Returns the EFI memory type if the region was found in the memory
Anshuman Khandual62b605b2020-01-13 18:22:41 +0100911 * map, -EINVAL otherwise.
Jan Beulich23f05712017-08-25 16:50:18 +0100912 */
913int efi_mem_type(unsigned long phys_addr)
914{
915 const efi_memory_desc_t *md;
916
917 if (!efi_enabled(EFI_MEMMAP))
918 return -ENOTSUPP;
919
920 for_each_efi_memory_desc(md) {
921 if ((md->phys_addr <= phys_addr) &&
922 (phys_addr < (md->phys_addr +
923 (md->num_pages << EFI_PAGE_SHIFT))))
924 return md->type;
925 }
926 return -EINVAL;
927}
928#endif
929
Matt Fleming806b0352016-04-25 21:06:58 +0100930int efi_status_to_err(efi_status_t status)
931{
932 int err;
933
934 switch (status) {
935 case EFI_SUCCESS:
936 err = 0;
937 break;
938 case EFI_INVALID_PARAMETER:
939 err = -EINVAL;
940 break;
941 case EFI_OUT_OF_RESOURCES:
942 err = -ENOSPC;
943 break;
944 case EFI_DEVICE_ERROR:
945 err = -EIO;
946 break;
947 case EFI_WRITE_PROTECTED:
948 err = -EROFS;
949 break;
950 case EFI_SECURITY_VIOLATION:
951 err = -EACCES;
952 break;
953 case EFI_NOT_FOUND:
954 err = -ENOENT;
955 break;
Ard Biesheuveldce48e32016-07-15 21:36:31 +0200956 case EFI_ABORTED:
957 err = -EINTR;
958 break;
Matt Fleming806b0352016-04-25 21:06:58 +0100959 default:
960 err = -EINVAL;
961 }
962
963 return err;
964}
Ard Biesheuvel63625982016-11-12 21:32:31 +0000965
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700966static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
Ard Biesheuvel63eb3222018-11-14 09:55:44 -0800967static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700968
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100969static int __init efi_memreserve_map_root(void)
970{
971 if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR)
972 return -ENODEV;
973
974 efi_memreserve_root = memremap(efi.mem_reserve,
975 sizeof(*efi_memreserve_root),
976 MEMREMAP_WB);
977 if (WARN_ON_ONCE(!efi_memreserve_root))
978 return -ENOMEM;
979 return 0;
980}
981
Ard Biesheuvelab0eb162019-12-06 16:55:37 +0000982static int efi_mem_reserve_iomem(phys_addr_t addr, u64 size)
983{
984 struct resource *res, *parent;
985
986 res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
987 if (!res)
988 return -ENOMEM;
989
990 res->name = "reserved";
991 res->flags = IORESOURCE_MEM;
992 res->start = addr;
993 res->end = addr + size - 1;
994
995 /* we expect a conflict with a 'System RAM' region */
996 parent = request_resource_conflict(&iomem_resource, res);
997 return parent ? request_resource(parent, res) : 0;
998}
999
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001000int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001001{
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001002 struct linux_efi_memreserve *rsv;
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001003 unsigned long prsv;
1004 int rc, index;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001005
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001006 if (efi_memreserve_root == (void *)ULONG_MAX)
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001007 return -ENODEV;
1008
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001009 if (!efi_memreserve_root) {
1010 rc = efi_memreserve_map_root();
1011 if (rc)
1012 return rc;
1013 }
1014
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001015 /* first try to find a slot in an existing linked list entry */
1016 for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
Ard Biesheuvel18df7572019-06-09 20:17:44 +02001017 rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001018 index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
1019 if (index < rsv->size) {
1020 rsv->entry[index].base = addr;
1021 rsv->entry[index].size = size;
1022
Ard Biesheuvel18df7572019-06-09 20:17:44 +02001023 memunmap(rsv);
Ard Biesheuvelab0eb162019-12-06 16:55:37 +00001024 return efi_mem_reserve_iomem(addr, size);
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001025 }
Ard Biesheuvel18df7572019-06-09 20:17:44 +02001026 memunmap(rsv);
Ard Biesheuvel80424b02018-11-29 18:12:29 +01001027 }
1028
1029 /* no slot found - allocate a new linked list entry */
1030 rsv = (struct linux_efi_memreserve *)__get_free_page(GFP_ATOMIC);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001031 if (!rsv)
1032 return -ENOMEM;
1033
Ard Biesheuvelab0eb162019-12-06 16:55:37 +00001034 rc = efi_mem_reserve_iomem(__pa(rsv), SZ_4K);
1035 if (rc) {
1036 free_page((unsigned long)rsv);
1037 return rc;
1038 }
1039
Ard Biesheuvel18df7572019-06-09 20:17:44 +02001040 /*
1041 * The memremap() call above assumes that a linux_efi_memreserve entry
1042 * never crosses a page boundary, so let's ensure that this remains true
1043 * even when kexec'ing a 4k pages kernel from a >4k pages kernel, by
1044 * using SZ_4K explicitly in the size calculation below.
1045 */
1046 rsv->size = EFI_MEMRESERVE_COUNT(SZ_4K);
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +01001047 atomic_set(&rsv->count, 1);
1048 rsv->entry[0].base = addr;
1049 rsv->entry[0].size = size;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001050
1051 spin_lock(&efi_mem_reserve_persistent_lock);
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001052 rsv->next = efi_memreserve_root->next;
1053 efi_memreserve_root->next = __pa(rsv);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001054 spin_unlock(&efi_mem_reserve_persistent_lock);
1055
Ard Biesheuvelab0eb162019-12-06 16:55:37 +00001056 return efi_mem_reserve_iomem(addr, size);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001057}
1058
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001059static int __init efi_memreserve_root_init(void)
1060{
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001061 if (efi_memreserve_root)
1062 return 0;
1063 if (efi_memreserve_map_root())
1064 efi_memreserve_root = (void *)ULONG_MAX;
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001065 return 0;
1066}
1067early_initcall(efi_memreserve_root_init);
1068
Ard Biesheuvel63625982016-11-12 21:32:31 +00001069#ifdef CONFIG_KEXEC
1070static int update_efi_random_seed(struct notifier_block *nb,
1071 unsigned long code, void *unused)
1072{
1073 struct linux_efi_random_seed *seed;
1074 u32 size = 0;
1075
1076 if (!kexec_in_progress)
1077 return NOTIFY_DONE;
1078
1079 seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB);
1080 if (seed != NULL) {
Ard Biesheuvelc2ceb5f2017-08-25 16:50:16 +01001081 size = min(seed->size, EFI_RANDOM_SEED_SIZE);
Ard Biesheuvel63625982016-11-12 21:32:31 +00001082 memunmap(seed);
1083 } else {
1084 pr_err("Could not map UEFI random seed!\n");
1085 }
1086 if (size > 0) {
1087 seed = memremap(efi.rng_seed, sizeof(*seed) + size,
1088 MEMREMAP_WB);
1089 if (seed != NULL) {
1090 seed->size = size;
1091 get_random_bytes(seed->bits, seed->size);
1092 memunmap(seed);
1093 } else {
1094 pr_err("Could not map UEFI random seed!\n");
1095 }
1096 }
1097 return NOTIFY_DONE;
1098}
1099
1100static struct notifier_block efi_random_seed_nb = {
1101 .notifier_call = update_efi_random_seed,
1102};
1103
1104static int register_update_efi_random_seed(void)
1105{
1106 if (efi.rng_seed == EFI_INVALID_TABLE_ADDR)
1107 return 0;
1108 return register_reboot_notifier(&efi_random_seed_nb);
1109}
1110late_initcall(register_update_efi_random_seed);
1111#endif