blob: 718dddfa0a0b3786470922bf1414a5dac71d6f56 [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 .acpi = EFI_INVALID_TABLE_ADDR,
39 .acpi20 = EFI_INVALID_TABLE_ADDR,
40 .smbios = EFI_INVALID_TABLE_ADDR,
41 .smbios3 = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvelbf924862015-09-09 10:08:15 +020042 .esrt = EFI_INVALID_TABLE_ADDR,
Ard Biesheuvel71e09402018-09-21 09:32:44 -070043 .tpm_log = EFI_INVALID_TABLE_ADDR,
Matthew Garrettc46f3402019-05-20 13:54:59 -070044 .tpm_final_log = EFI_INVALID_TABLE_ADDR,
Leif Lindholm272686b2013-09-05 11:34:54 +010045};
46EXPORT_SYMBOL(efi);
Tom Gundersena9499fa2013-02-08 15:37:06 +000047
Ard Biesheuvel5d288db2020-01-22 14:58:15 +010048static unsigned long __ro_after_init rng_seed = EFI_INVALID_TABLE_ADDR;
Ard Biesheuvelb7846e62020-01-22 15:06:54 +010049static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
Ard Biesheuvel5d288db2020-01-22 14:58:15 +010050
Sai Praneeth7e904a92018-03-12 08:44:56 +000051struct mm_struct efi_mm = {
52 .mm_rb = RB_ROOT,
53 .mm_users = ATOMIC_INIT(2),
54 .mm_count = ATOMIC_INIT(1),
55 .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
56 .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
57 .mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
Rik van Rielc1a2f7f2018-07-16 15:03:31 -040058 .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0},
Sai Praneeth7e904a92018-03-12 08:44:56 +000059};
60
Sai Praneeth3eb420e2018-07-11 11:40:35 +020061struct workqueue_struct *efi_rts_wq;
62
Dave Youngb2e0a542014-08-14 17:15:26 +080063static bool disable_runtime;
64static int __init setup_noefi(char *arg)
65{
66 disable_runtime = true;
67 return 0;
68}
69early_param("noefi", setup_noefi);
70
71bool efi_runtime_disabled(void)
72{
73 return disable_runtime;
74}
75
Dan Williamsb617c522019-11-06 17:43:11 -080076bool __pure __efi_soft_reserve_enabled(void)
77{
78 return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE);
79}
80
Dave Young5ae36832014-08-14 17:15:28 +080081static int __init parse_efi_cmdline(char *str)
82{
Ricardo Neri9115c752015-07-15 19:36:03 -070083 if (!str) {
84 pr_warn("need at least one option\n");
85 return -EINVAL;
86 }
87
Leif Lindholm12dd00e2015-08-26 14:24:56 +010088 if (parse_option_str(str, "debug"))
89 set_bit(EFI_DBG, &efi.flags);
90
Dave Young5ae36832014-08-14 17:15:28 +080091 if (parse_option_str(str, "noruntime"))
92 disable_runtime = true;
93
Dan Williamsb617c522019-11-06 17:43:11 -080094 if (parse_option_str(str, "nosoftreserve"))
95 set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
96
Dave Young5ae36832014-08-14 17:15:28 +080097 return 0;
98}
99early_param("efi", parse_efi_cmdline);
100
Peter Jones0bb54902015-04-28 18:44:31 -0400101struct kobject *efi_kobj;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000102
103/*
104 * Let's not leave out systab information that snuck into
105 * the efivars driver
Dave Young0b02e442017-12-06 09:50:10 +0000106 * Note, do not add more fields in systab sysfs file as it breaks sysfs
107 * one value per file rule!
Tom Gundersena9499fa2013-02-08 15:37:06 +0000108 */
109static ssize_t systab_show(struct kobject *kobj,
110 struct kobj_attribute *attr, char *buf)
111{
112 char *str = buf;
113
114 if (!kobj || !buf)
115 return -EINVAL;
116
Tom Gundersena9499fa2013-02-08 15:37:06 +0000117 if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
118 str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
119 if (efi.acpi != EFI_INVALID_TABLE_ADDR)
120 str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
Jean Delvareb119fe02015-04-30 15:23:05 +0200121 /*
122 * If both SMBIOS and SMBIOS3 entry points are implemented, the
123 * SMBIOS3 entry point shall be preferred, so we list it first to
124 * let applications stop parsing after the first match.
125 */
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200126 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
127 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
Jean Delvareb119fe02015-04-30 15:23:05 +0200128 if (efi.smbios != EFI_INVALID_TABLE_ADDR)
129 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
Tom Gundersena9499fa2013-02-08 15:37:06 +0000130
Ard Biesheuvelfd506e02020-01-19 16:17:59 +0100131 if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86)) {
Ard Biesheuvel120540f2020-01-19 15:43:53 +0100132 extern char *efi_systab_show_arch(char *str);
133
134 str = efi_systab_show_arch(str);
135 }
136
Tom Gundersena9499fa2013-02-08 15:37:06 +0000137 return str - buf;
138}
139
Greg Kroah-Hartmanaf97a772017-12-06 09:50:08 +0000140static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
Tom Gundersena9499fa2013-02-08 15:37:06 +0000141
Steve McIntyre2859dff2015-01-09 15:29:53 +0000142static ssize_t fw_platform_size_show(struct kobject *kobj,
143 struct kobj_attribute *attr, char *buf)
144{
145 return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
146}
147
Ard Biesheuvel9cd437a2020-01-20 17:23:21 +0100148extern __weak struct kobj_attribute efi_attr_fw_vendor;
149extern __weak struct kobj_attribute efi_attr_runtime;
150extern __weak struct kobj_attribute efi_attr_config_table;
Steve McIntyre2859dff2015-01-09 15:29:53 +0000151static struct kobj_attribute efi_attr_fw_platform_size =
152 __ATTR_RO(fw_platform_size);
Dave Younga0998eb2013-12-20 18:02:17 +0800153
Tom Gundersena9499fa2013-02-08 15:37:06 +0000154static struct attribute *efi_subsys_attrs[] = {
155 &efi_attr_systab.attr,
Ard Biesheuvel9cd437a2020-01-20 17:23:21 +0100156 &efi_attr_fw_platform_size.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800157 &efi_attr_fw_vendor.attr,
158 &efi_attr_runtime.attr,
159 &efi_attr_config_table.attr,
160 NULL,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000161};
162
Ard Biesheuvel9cd437a2020-01-20 17:23:21 +0100163umode_t __weak efi_attr_is_visible(struct kobject *kobj, struct attribute *attr,
164 int n)
Dave Younga0998eb2013-12-20 18:02:17 +0800165{
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200166 return attr->mode;
Dave Younga0998eb2013-12-20 18:02:17 +0800167}
168
Arvind Yadav3ad6bd72017-08-18 20:49:46 +0100169static const struct attribute_group efi_subsys_attr_group = {
Tom Gundersena9499fa2013-02-08 15:37:06 +0000170 .attrs = efi_subsys_attrs,
Dave Younga0998eb2013-12-20 18:02:17 +0800171 .is_visible = efi_attr_is_visible,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000172};
173
174static struct efivars generic_efivars;
175static struct efivar_operations generic_ops;
176
177static int generic_ops_register(void)
178{
179 generic_ops.get_variable = efi.get_variable;
180 generic_ops.set_variable = efi.set_variable;
Ard Biesheuvel9c6672a2016-02-01 22:06:55 +0000181 generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000182 generic_ops.get_next_variable = efi.get_next_variable;
Matt Fleminga614e192013-04-30 11:30:24 +0100183 generic_ops.query_variable_store = efi_query_variable_store;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000184
185 return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
186}
187
188static void generic_ops_unregister(void)
189{
190 efivars_unregister(&generic_efivars);
191}
192
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300193#if IS_ENABLED(CONFIG_ACPI)
194#define EFIVAR_SSDT_NAME_MAX 16
195static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
196static int __init efivar_ssdt_setup(char *str)
197{
Matthew Garrett1957a85b2019-08-19 17:18:04 -0700198 int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
199
200 if (ret)
201 return ret;
202
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300203 if (strlen(str) < sizeof(efivar_ssdt))
204 memcpy(efivar_ssdt, str, strlen(str));
205 else
206 pr_warn("efivar_ssdt: name too long: %s\n", str);
207 return 0;
208}
209__setup("efivar_ssdt=", efivar_ssdt_setup);
210
211static __init int efivar_ssdt_iter(efi_char16_t *name, efi_guid_t vendor,
212 unsigned long name_size, void *data)
213{
214 struct efivar_entry *entry;
215 struct list_head *list = data;
216 char utf8_name[EFIVAR_SSDT_NAME_MAX];
217 int limit = min_t(unsigned long, EFIVAR_SSDT_NAME_MAX, name_size);
218
219 ucs2_as_utf8(utf8_name, name, limit - 1);
220 if (strncmp(utf8_name, efivar_ssdt, limit) != 0)
221 return 0;
222
223 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
224 if (!entry)
225 return 0;
226
227 memcpy(entry->var.VariableName, name, name_size);
228 memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t));
229
230 efivar_entry_add(entry, list);
231
232 return 0;
233}
234
235static __init int efivar_ssdt_load(void)
236{
237 LIST_HEAD(entries);
238 struct efivar_entry *entry, *aux;
239 unsigned long size;
240 void *data;
241 int ret;
242
Ard Biesheuvelc05f8f92019-10-02 18:58:59 +0200243 if (!efivar_ssdt[0])
244 return 0;
245
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300246 ret = efivar_init(efivar_ssdt_iter, &entries, true, &entries);
247
248 list_for_each_entry_safe(entry, aux, &entries, list) {
249 pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt,
250 &entry->var.VendorGuid);
251
252 list_del(&entry->list);
253
254 ret = efivar_entry_size(entry, &size);
255 if (ret) {
256 pr_err("failed to get var size\n");
257 goto free_entry;
258 }
259
260 data = kmalloc(size, GFP_KERNEL);
Dan Carpentera75dcb52016-10-18 15:33:18 +0100261 if (!data) {
262 ret = -ENOMEM;
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300263 goto free_entry;
Dan Carpentera75dcb52016-10-18 15:33:18 +0100264 }
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300265
266 ret = efivar_entry_get(entry, NULL, &size, data);
267 if (ret) {
268 pr_err("failed to get var data\n");
269 goto free_data;
270 }
271
Nikolaus Voss17700932019-10-25 14:36:53 -0700272 ret = acpi_load_table(data, NULL);
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300273 if (ret) {
274 pr_err("failed to load table: %d\n", ret);
275 goto free_data;
276 }
277
278 goto free_entry;
279
280free_data:
281 kfree(data);
282
283free_entry:
284 kfree(entry);
285 }
286
287 return ret;
288}
289#else
290static inline int efivar_ssdt_load(void) { return 0; }
291#endif
292
Tom Gundersena9499fa2013-02-08 15:37:06 +0000293/*
294 * We register the efi subsystem with the firmware subsystem and the
295 * efivars subsystem with the efi subsystem, if the system was booted with
296 * EFI.
297 */
298static int __init efisubsys_init(void)
299{
300 int error;
301
302 if (!efi_enabled(EFI_BOOT))
303 return 0;
304
Sai Praneeth3eb420e2018-07-11 11:40:35 +0200305 /*
306 * Since we process only one efi_runtime_service() at a time, an
307 * ordered workqueue (which creates only one execution context)
308 * should suffice all our needs.
309 */
310 efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
311 if (!efi_rts_wq) {
312 pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
313 clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
314 return 0;
315 }
316
Tom Gundersena9499fa2013-02-08 15:37:06 +0000317 /* We register the efi directory at /sys/firmware/efi */
318 efi_kobj = kobject_create_and_add("efi", firmware_kobj);
319 if (!efi_kobj) {
320 pr_err("efi: Firmware registration failed.\n");
321 return -ENOMEM;
322 }
323
324 error = generic_ops_register();
325 if (error)
326 goto err_put;
327
Octavian Purdila475fb4e2016-07-08 19:13:12 +0300328 if (efi_enabled(EFI_RUNTIME_SERVICES))
329 efivar_ssdt_load();
330
Tom Gundersena9499fa2013-02-08 15:37:06 +0000331 error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
332 if (error) {
333 pr_err("efi: Sysfs attribute export failed with error %d.\n",
334 error);
335 goto err_unregister;
336 }
337
Dave Young926172d2013-12-20 18:02:18 +0800338 error = efi_runtime_map_init(efi_kobj);
339 if (error)
340 goto err_remove_group;
341
Tom Gundersena9499fa2013-02-08 15:37:06 +0000342 /* and the standard mountpoint for efivarfs */
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -0500343 error = sysfs_create_mount_point(efi_kobj, "efivars");
344 if (error) {
Tom Gundersena9499fa2013-02-08 15:37:06 +0000345 pr_err("efivars: Subsystem registration failed.\n");
Tom Gundersena9499fa2013-02-08 15:37:06 +0000346 goto err_remove_group;
347 }
348
349 return 0;
350
351err_remove_group:
352 sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
353err_unregister:
354 generic_ops_unregister();
355err_put:
356 kobject_put(efi_kobj);
357 return error;
358}
359
360subsys_initcall(efisubsys_init);
Leif Lindholm272686b2013-09-05 11:34:54 +0100361
Peter Jones0bb54902015-04-28 18:44:31 -0400362/*
363 * Find the efi memory descriptor for a given physical address. Given a
Matt Flemingdca0f972016-02-27 15:52:50 +0000364 * physical address, determine if it exists within an EFI Memory Map entry,
Peter Jones0bb54902015-04-28 18:44:31 -0400365 * and if so, populate the supplied memory descriptor with the appropriate
366 * data.
367 */
Ard Biesheuvel7e1550b2018-07-11 11:40:39 +0200368int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
Peter Jones0bb54902015-04-28 18:44:31 -0400369{
Matt Flemingdca0f972016-02-27 15:52:50 +0000370 efi_memory_desc_t *md;
Peter Jones0bb54902015-04-28 18:44:31 -0400371
372 if (!efi_enabled(EFI_MEMMAP)) {
373 pr_err_once("EFI_MEMMAP is not enabled.\n");
374 return -EINVAL;
375 }
376
Peter Jones0bb54902015-04-28 18:44:31 -0400377 if (!out_md) {
378 pr_err_once("out_md is null.\n");
379 return -EINVAL;
380 }
Peter Jones0bb54902015-04-28 18:44:31 -0400381
Matt Flemingdca0f972016-02-27 15:52:50 +0000382 for_each_efi_memory_desc(md) {
Peter Jones0bb54902015-04-28 18:44:31 -0400383 u64 size;
384 u64 end;
385
Peter Jones0bb54902015-04-28 18:44:31 -0400386 size = md->num_pages << EFI_PAGE_SHIFT;
387 end = md->phys_addr + size;
388 if (phys_addr >= md->phys_addr && phys_addr < end) {
389 memcpy(out_md, md, sizeof(*out_md));
Peter Jones0bb54902015-04-28 18:44:31 -0400390 return 0;
391 }
Peter Jones0bb54902015-04-28 18:44:31 -0400392 }
Peter Jones0bb54902015-04-28 18:44:31 -0400393 return -ENOENT;
394}
395
396/*
397 * Calculate the highest address of an efi memory descriptor.
398 */
399u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
400{
401 u64 size = md->num_pages << EFI_PAGE_SHIFT;
402 u64 end = md->phys_addr + size;
403 return end;
404}
Leif Lindholm272686b2013-09-05 11:34:54 +0100405
Matt Fleming816e7612016-02-29 21:22:52 +0000406void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {}
407
408/**
409 * efi_mem_reserve - Reserve an EFI memory region
410 * @addr: Physical address to reserve
411 * @size: Size of reservation
412 *
413 * Mark a region as reserved from general kernel allocation and
414 * prevent it being released by efi_free_boot_services().
415 *
416 * This function should be called drivers once they've parsed EFI
417 * configuration tables to figure out where their data lives, e.g.
418 * efi_esrt_init().
419 */
420void __init efi_mem_reserve(phys_addr_t addr, u64 size)
421{
422 if (!memblock_is_region_reserved(addr, size))
423 memblock_reserve(addr, size);
424
425 /*
426 * Some architectures (x86) reserve all boot services ranges
427 * until efi_free_boot_services() because of buggy firmware
428 * implementations. This means the above memblock_reserve() is
429 * superfluous on x86 and instead what it needs to do is
430 * ensure the @start, @size is not freed.
431 */
432 efi_arch_mem_reserve(addr, size);
433}
434
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100435static const efi_config_table_type_t common_tables[] __initconst = {
Leif Lindholm272686b2013-09-05 11:34:54 +0100436 {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
437 {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
Leif Lindholm272686b2013-09-05 11:34:54 +0100438 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200439 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
Peter Jones0bb54902015-04-28 18:44:31 -0400440 {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
Ard Biesheuvela17e8092020-01-22 15:05:12 +0100441 {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi_mem_attr_table},
Ard Biesheuvel5d288db2020-01-22 14:58:15 +0100442 {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &rng_seed},
Thiebaud Weksteen33b6d032017-09-20 10:13:39 +0200443 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
Matthew Garrettc46f3402019-05-20 13:54:59 -0700444 {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
Ard Biesheuvelb7846e62020-01-22 15:06:54 +0100445 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &mem_reserve},
Narendra K1c5fecb2019-07-10 18:59:15 +0000446#ifdef CONFIG_EFI_RCI2_TABLE
447 {DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys},
448#endif
Daeseok Youn69e60842014-02-13 17:16:36 +0900449 {NULL_GUID, NULL, NULL},
Leif Lindholm272686b2013-09-05 11:34:54 +0100450};
451
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100452static __init int match_config_table(const efi_guid_t *guid,
Leif Lindholm272686b2013-09-05 11:34:54 +0100453 unsigned long table,
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100454 const efi_config_table_type_t *table_types)
Leif Lindholm272686b2013-09-05 11:34:54 +0100455{
Leif Lindholm272686b2013-09-05 11:34:54 +0100456 int i;
457
458 if (table_types) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100459 for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100460 if (!efi_guidcmp(*guid, table_types[i].guid)) {
461 *(table_types[i].ptr) = table;
Ard Biesheuvel801820b2016-04-25 21:06:53 +0100462 if (table_types[i].name)
463 pr_cont(" %s=0x%lx ",
464 table_types[i].name, table);
Leif Lindholm272686b2013-09-05 11:34:54 +0100465 return 1;
466 }
467 }
468 }
469
470 return 0;
471}
472
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100473int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
474 int count,
475 const efi_config_table_type_t *arch_tables)
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200476{
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100477 const efi_config_table_64_t *tbl64 = (void *)config_tables;
478 const efi_config_table_32_t *tbl32 = (void *)config_tables;
479 const efi_guid_t *guid;
480 unsigned long table;
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200481 int i;
482
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200483 pr_info("");
484 for (i = 0; i < count; i++) {
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100485 if (!IS_ENABLED(CONFIG_X86)) {
486 guid = &config_tables[i].guid;
487 table = (unsigned long)config_tables[i].table;
488 } else if (efi_enabled(EFI_64BIT)) {
489 guid = &tbl64[i].guid;
490 table = tbl64[i].table;
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200491
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100492 if (IS_ENABLED(CONFIG_X86_32) &&
493 tbl64[i].table > U32_MAX) {
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200494 pr_cont("\n");
495 pr_err("Table located above 4GB, disabling EFI.\n");
496 return -EINVAL;
497 }
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200498 } else {
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100499 guid = &tbl32[i].guid;
500 table = tbl32[i].table;
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200501 }
502
Ard Biesheuvel06c0bd92020-01-22 14:40:57 +0100503 if (!match_config_table(guid, table, common_tables))
504 match_config_table(guid, table, arch_tables);
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200505 }
506 pr_cont("\n");
507 set_bit(EFI_CONFIG_TABLES, &efi.flags);
Ard Biesheuvela1041712015-09-23 07:29:34 -0700508
Ard Biesheuvel5d288db2020-01-22 14:58:15 +0100509 if (rng_seed != EFI_INVALID_TABLE_ADDR) {
Ard Biesheuvel63625982016-11-12 21:32:31 +0000510 struct linux_efi_random_seed *seed;
511 u32 size = 0;
512
Ard Biesheuvel5d288db2020-01-22 14:58:15 +0100513 seed = early_memremap(rng_seed, sizeof(*seed));
Ard Biesheuvel63625982016-11-12 21:32:31 +0000514 if (seed != NULL) {
515 size = seed->size;
516 early_memunmap(seed, sizeof(*seed));
517 } else {
518 pr_err("Could not map UEFI random seed!\n");
519 }
520 if (size > 0) {
Ard Biesheuvel5d288db2020-01-22 14:58:15 +0100521 seed = early_memremap(rng_seed, sizeof(*seed) + size);
Ard Biesheuvel63625982016-11-12 21:32:31 +0000522 if (seed != NULL) {
Ard Biesheuvel5b4e4c32018-03-08 08:00:18 +0000523 pr_notice("seeding entropy pool\n");
Dominik Brodowski18b915a2019-10-29 18:37:52 +0100524 add_bootloader_randomness(seed->bits, seed->size);
Ard Biesheuvel63625982016-11-12 21:32:31 +0000525 early_memunmap(seed, sizeof(*seed) + size);
526 } else {
527 pr_err("Could not map UEFI random seed!\n");
528 }
529 }
530 }
531
Daniel Kiper457ea3f2017-06-22 12:51:36 +0200532 if (efi_enabled(EFI_MEMMAP))
533 efi_memattr_init();
Sai Praneeth3a6b6c62017-01-31 13:21:35 +0000534
Thiebaud Weksteen33b6d032017-09-20 10:13:39 +0200535 efi_tpm_eventlog_init();
536
Ard Biesheuvelb7846e62020-01-22 15:06:54 +0100537 if (mem_reserve != EFI_INVALID_TABLE_ADDR) {
538 unsigned long prsv = mem_reserve;
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700539
540 while (prsv) {
541 struct linux_efi_memreserve *rsv;
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100542 u8 *p;
543 int i;
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700544
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100545 /*
546 * Just map a full page: that is what we will get
547 * anyway, and it permits us to map the entire entry
548 * before knowing its size.
549 */
550 p = early_memremap(ALIGN_DOWN(prsv, PAGE_SIZE),
551 PAGE_SIZE);
552 if (p == NULL) {
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700553 pr_err("Could not map UEFI memreserve entry!\n");
554 return -ENOMEM;
555 }
556
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100557 rsv = (void *)(p + prsv % PAGE_SIZE);
558
559 /* reserve the entry itself */
560 memblock_reserve(prsv, EFI_MEMRESERVE_SIZE(rsv->size));
561
562 for (i = 0; i < atomic_read(&rsv->count); i++) {
563 memblock_reserve(rsv->entry[i].base,
564 rsv->entry[i].size);
565 }
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700566
567 prsv = rsv->next;
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +0100568 early_memunmap(p, PAGE_SIZE);
Ard Biesheuvel71e09402018-09-21 09:32:44 -0700569 }
570 }
571
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200572 return 0;
573}
574
Ard Biesheuvel14fb4202020-01-20 10:49:11 +0100575int __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr,
576 int min_major_version)
577{
578 if (systab_hdr->signature != EFI_SYSTEM_TABLE_SIGNATURE) {
579 pr_err("System table signature incorrect!\n");
580 return -EINVAL;
581 }
582
583 if ((systab_hdr->revision >> 16) < min_major_version)
584 pr_err("Warning: System table version %d.%02d, expected %d.00 or greater!\n",
585 systab_hdr->revision >> 16,
586 systab_hdr->revision & 0xffff,
587 min_major_version);
588
589 return 0;
590}
591
592#ifndef CONFIG_IA64
593static const efi_char16_t *__init map_fw_vendor(unsigned long fw_vendor,
594 size_t size)
595{
596 const efi_char16_t *ret;
597
598 ret = early_memremap_ro(fw_vendor, size);
599 if (!ret)
600 pr_err("Could not map the firmware vendor!\n");
601 return ret;
602}
603
604static void __init unmap_fw_vendor(const void *fw_vendor, size_t size)
605{
606 early_memunmap((void *)fw_vendor, size);
607}
608#else
609#define map_fw_vendor(p, s) __va(p)
610#define unmap_fw_vendor(v, s)
611#endif
612
613void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
614 unsigned long fw_vendor)
615{
616 char vendor[100] = "unknown";
617 const efi_char16_t *c16;
618 size_t i;
619
620 c16 = map_fw_vendor(fw_vendor, sizeof(vendor) * sizeof(efi_char16_t));
621 if (c16) {
622 for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
623 vendor[i] = c16[i];
624 vendor[i] = '\0';
625
626 unmap_fw_vendor(c16, sizeof(vendor) * sizeof(efi_char16_t));
627 }
628
629 pr_info("EFI v%u.%.02u by %s\n",
630 systab_hdr->revision >> 16,
631 systab_hdr->revision & 0xffff,
632 vendor);
633}
634
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800635#ifdef CONFIG_EFI_VARS_MODULE
636static int __init efi_load_efivars(void)
637{
638 struct platform_device *pdev;
639
640 if (!efi_enabled(EFI_RUNTIME_SERVICES))
641 return 0;
642
643 pdev = platform_device_register_simple("efivars", 0, NULL, 0);
Vasyl Gomonovych50342b22018-01-02 18:10:40 +0000644 return PTR_ERR_OR_ZERO(pdev);
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800645}
646device_initcall(efi_load_efivars);
647#endif
648
Mark Salter0302f712013-12-30 12:12:12 -0500649#ifdef CONFIG_EFI_PARAMS_FROM_FDT
650
651#define UEFI_PARAM(name, prop, field) \
652 { \
653 { name }, \
654 { prop }, \
655 offsetof(struct efi_fdt_params, field), \
Pankaj Bharadiyac5936422019-12-09 10:31:43 -0800656 sizeof_field(struct efi_fdt_params, field) \
Mark Salter0302f712013-12-30 12:12:12 -0500657 }
658
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800659struct params {
Mark Salter0302f712013-12-30 12:12:12 -0500660 const char name[32];
661 const char propname[32];
662 int offset;
663 int size;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800664};
665
666static __initdata struct params fdt_params[] = {
Mark Salter0302f712013-12-30 12:12:12 -0500667 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
668 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
669 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
670 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
671 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
672};
673
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800674static __initdata struct params xen_fdt_params[] = {
675 UEFI_PARAM("System Table", "xen,uefi-system-table", system_table),
676 UEFI_PARAM("MemMap Address", "xen,uefi-mmap-start", mmap),
677 UEFI_PARAM("MemMap Size", "xen,uefi-mmap-size", mmap_size),
678 UEFI_PARAM("MemMap Desc. Size", "xen,uefi-mmap-desc-size", desc_size),
679 UEFI_PARAM("MemMap Desc. Version", "xen,uefi-mmap-desc-ver", desc_ver)
680};
681
682#define EFI_FDT_PARAMS_SIZE ARRAY_SIZE(fdt_params)
683
684static __initdata struct {
685 const char *uname;
686 const char *subnode;
687 struct params *params;
688} dt_params[] = {
689 { "hypervisor", "uefi", xen_fdt_params },
690 { "chosen", NULL, fdt_params },
691};
692
Mark Salter0302f712013-12-30 12:12:12 -0500693struct param_info {
Catalin Marinas29e24352014-07-08 16:54:18 +0100694 int found;
Mark Salter0302f712013-12-30 12:12:12 -0500695 void *params;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800696 const char *missing;
Mark Salter0302f712013-12-30 12:12:12 -0500697};
698
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800699static int __init __find_uefi_params(unsigned long node,
700 struct param_info *info,
701 struct params *params)
Mark Salter0302f712013-12-30 12:12:12 -0500702{
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100703 const void *prop;
704 void *dest;
Mark Salter0302f712013-12-30 12:12:12 -0500705 u64 val;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100706 int i, len;
Mark Salter0302f712013-12-30 12:12:12 -0500707
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800708 for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) {
709 prop = of_get_flat_dt_prop(node, params[i].propname, &len);
710 if (!prop) {
711 info->missing = params[i].name;
Mark Salter0302f712013-12-30 12:12:12 -0500712 return 0;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800713 }
714
715 dest = info->params + params[i].offset;
Catalin Marinas29e24352014-07-08 16:54:18 +0100716 info->found++;
Mark Salter0302f712013-12-30 12:12:12 -0500717
718 val = of_read_number(prop, len / sizeof(u32));
719
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800720 if (params[i].size == sizeof(u32))
Mark Salter0302f712013-12-30 12:12:12 -0500721 *(u32 *)dest = val;
722 else
723 *(u64 *)dest = val;
724
Leif Lindholm7968c0e2015-08-26 14:24:58 +0100725 if (efi_enabled(EFI_DBG))
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800726 pr_info(" %s: 0x%0*llx\n", params[i].name,
727 params[i].size * 2, val);
Mark Salter0302f712013-12-30 12:12:12 -0500728 }
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800729
Mark Salter0302f712013-12-30 12:12:12 -0500730 return 1;
731}
732
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800733static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
734 int depth, void *data)
735{
736 struct param_info *info = data;
737 int i;
738
739 for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
740 const char *subnode = dt_params[i].subnode;
741
742 if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) {
743 info->missing = dt_params[i].params[0].name;
744 continue;
745 }
746
747 if (subnode) {
Andrzej Hajda4af9ed52016-08-30 12:41:37 +0200748 int err = of_get_flat_dt_subnode_by_name(node, subnode);
749
750 if (err < 0)
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800751 return 0;
Andrzej Hajda4af9ed52016-08-30 12:41:37 +0200752
753 node = err;
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800754 }
755
756 return __find_uefi_params(node, info, dt_params[i].params);
757 }
758
759 return 0;
760}
761
Leif Lindholm7968c0e2015-08-26 14:24:58 +0100762int __init efi_get_fdt_params(struct efi_fdt_params *params)
Mark Salter0302f712013-12-30 12:12:12 -0500763{
764 struct param_info info;
Catalin Marinas29e24352014-07-08 16:54:18 +0100765 int ret;
766
767 pr_info("Getting EFI parameters from FDT:\n");
Mark Salter0302f712013-12-30 12:12:12 -0500768
Catalin Marinas29e24352014-07-08 16:54:18 +0100769 info.found = 0;
Mark Salter0302f712013-12-30 12:12:12 -0500770 info.params = params;
771
Catalin Marinas29e24352014-07-08 16:54:18 +0100772 ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
773 if (!info.found)
774 pr_info("UEFI not found.\n");
775 else if (!ret)
776 pr_err("Can't find '%s' in device tree!\n",
Shannon Zhao0cac5c32016-05-12 20:19:54 +0800777 info.missing);
Catalin Marinas29e24352014-07-08 16:54:18 +0100778
779 return ret;
Mark Salter0302f712013-12-30 12:12:12 -0500780}
781#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200782
783static __initdata char memory_type_name[][20] = {
784 "Reserved",
785 "Loader Code",
786 "Loader Data",
787 "Boot Code",
788 "Boot Data",
789 "Runtime Code",
790 "Runtime Data",
791 "Conventional Memory",
792 "Unusable Memory",
793 "ACPI Reclaim Memory",
794 "ACPI Memory NVS",
795 "Memory Mapped I/O",
796 "MMIO Port Space",
Robert Elliott35575e02016-02-01 22:07:07 +0000797 "PAL Code",
798 "Persistent Memory",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200799};
800
801char * __init efi_md_typeattr_format(char *buf, size_t size,
802 const efi_memory_desc_t *md)
803{
804 char *pos;
805 int type_len;
806 u64 attr;
807
808 pos = buf;
809 if (md->type >= ARRAY_SIZE(memory_type_name))
810 type_len = snprintf(pos, size, "[type=%u", md->type);
811 else
812 type_len = snprintf(pos, size, "[%-*s",
813 (int)(sizeof(memory_type_name[0]) - 1),
814 memory_type_name[md->type]);
815 if (type_len >= size)
816 return buf;
817
818 pos += type_len;
819 size -= type_len;
820
821 attr = md->attribute;
822 if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
Ard Biesheuvel87db73ae2015-08-07 09:36:54 +0100823 EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
824 EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
Dan Williamsfe3e5e62019-11-06 17:43:00 -0800825 EFI_MEMORY_NV | EFI_MEMORY_SP |
Taku Izumi8be44322015-08-27 02:11:19 +0900826 EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200827 snprintf(pos, size, "|attr=0x%016llx]",
828 (unsigned long long)attr);
829 else
Robert Elliottc016ca02016-02-01 22:07:06 +0000830 snprintf(pos, size,
Dan Williamsfe3e5e62019-11-06 17:43:00 -0800831 "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200832 attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
Taku Izumi8be44322015-08-27 02:11:19 +0900833 attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
Dan Williamsfe3e5e62019-11-06 17:43:00 -0800834 attr & EFI_MEMORY_SP ? "SP" : "",
Robert Elliottc016ca02016-02-01 22:07:06 +0000835 attr & EFI_MEMORY_NV ? "NV" : "",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200836 attr & EFI_MEMORY_XP ? "XP" : "",
837 attr & EFI_MEMORY_RP ? "RP" : "",
838 attr & EFI_MEMORY_WP ? "WP" : "",
Ard Biesheuvel87db73ae2015-08-07 09:36:54 +0100839 attr & EFI_MEMORY_RO ? "RO" : "",
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200840 attr & EFI_MEMORY_UCE ? "UCE" : "",
841 attr & EFI_MEMORY_WB ? "WB" : "",
842 attr & EFI_MEMORY_WT ? "WT" : "",
843 attr & EFI_MEMORY_WC ? "WC" : "",
844 attr & EFI_MEMORY_UC ? "UC" : "");
845 return buf;
846}
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100847
848/*
Jan Beulich23f05712017-08-25 16:50:18 +0100849 * IA64 has a funky EFI memory map that doesn't work the same way as
850 * other architectures.
851 */
852#ifndef CONFIG_IA64
853/*
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100854 * efi_mem_attributes - lookup memmap attributes for physical address
855 * @phys_addr: the physical address to lookup
856 *
857 * Search in the EFI memory map for the region covering
858 * @phys_addr. Returns the EFI memory attributes if the region
859 * was found in the memory map, 0 otherwise.
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100860 */
Jan Beulich23f05712017-08-25 16:50:18 +0100861u64 efi_mem_attributes(unsigned long phys_addr)
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100862{
863 efi_memory_desc_t *md;
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100864
865 if (!efi_enabled(EFI_MEMMAP))
866 return 0;
867
Matt Fleming78ce2482016-04-25 21:06:38 +0100868 for_each_efi_memory_desc(md) {
Jonathan (Zhixiong) Zhang7bf79312015-08-07 09:36:57 +0100869 if ((md->phys_addr <= phys_addr) &&
870 (phys_addr < (md->phys_addr +
871 (md->num_pages << EFI_PAGE_SHIFT))))
872 return md->attribute;
873 }
874 return 0;
875}
Matt Fleming806b0352016-04-25 21:06:58 +0100876
Jan Beulich23f05712017-08-25 16:50:18 +0100877/*
878 * efi_mem_type - lookup memmap type for physical address
879 * @phys_addr: the physical address to lookup
880 *
881 * Search in the EFI memory map for the region covering @phys_addr.
882 * Returns the EFI memory type if the region was found in the memory
Anshuman Khandual62b605b2020-01-13 18:22:41 +0100883 * map, -EINVAL otherwise.
Jan Beulich23f05712017-08-25 16:50:18 +0100884 */
885int efi_mem_type(unsigned long phys_addr)
886{
887 const efi_memory_desc_t *md;
888
889 if (!efi_enabled(EFI_MEMMAP))
890 return -ENOTSUPP;
891
892 for_each_efi_memory_desc(md) {
893 if ((md->phys_addr <= phys_addr) &&
894 (phys_addr < (md->phys_addr +
895 (md->num_pages << EFI_PAGE_SHIFT))))
896 return md->type;
897 }
898 return -EINVAL;
899}
900#endif
901
Matt Fleming806b0352016-04-25 21:06:58 +0100902int efi_status_to_err(efi_status_t status)
903{
904 int err;
905
906 switch (status) {
907 case EFI_SUCCESS:
908 err = 0;
909 break;
910 case EFI_INVALID_PARAMETER:
911 err = -EINVAL;
912 break;
913 case EFI_OUT_OF_RESOURCES:
914 err = -ENOSPC;
915 break;
916 case EFI_DEVICE_ERROR:
917 err = -EIO;
918 break;
919 case EFI_WRITE_PROTECTED:
920 err = -EROFS;
921 break;
922 case EFI_SECURITY_VIOLATION:
923 err = -EACCES;
924 break;
925 case EFI_NOT_FOUND:
926 err = -ENOENT;
927 break;
Ard Biesheuveldce48e32016-07-15 21:36:31 +0200928 case EFI_ABORTED:
929 err = -EINTR;
930 break;
Matt Fleming806b0352016-04-25 21:06:58 +0100931 default:
932 err = -EINVAL;
933 }
934
935 return err;
936}
Ard Biesheuvel63625982016-11-12 21:32:31 +0000937
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700938static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
Ard Biesheuvel63eb3222018-11-14 09:55:44 -0800939static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700940
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100941static int __init efi_memreserve_map_root(void)
942{
Ard Biesheuvelb7846e62020-01-22 15:06:54 +0100943 if (mem_reserve == EFI_INVALID_TABLE_ADDR)
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100944 return -ENODEV;
945
Ard Biesheuvelb7846e62020-01-22 15:06:54 +0100946 efi_memreserve_root = memremap(mem_reserve,
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100947 sizeof(*efi_memreserve_root),
948 MEMREMAP_WB);
949 if (WARN_ON_ONCE(!efi_memreserve_root))
950 return -ENOMEM;
951 return 0;
952}
953
Ard Biesheuvelab0eb162019-12-06 16:55:37 +0000954static int efi_mem_reserve_iomem(phys_addr_t addr, u64 size)
955{
956 struct resource *res, *parent;
957
958 res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
959 if (!res)
960 return -ENOMEM;
961
962 res->name = "reserved";
963 res->flags = IORESOURCE_MEM;
964 res->start = addr;
965 res->end = addr + size - 1;
966
967 /* we expect a conflict with a 'System RAM' region */
968 parent = request_resource_conflict(&iomem_resource, res);
969 return parent ? request_resource(parent, res) : 0;
970}
971
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100972int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700973{
Ard Biesheuvel63eb3222018-11-14 09:55:44 -0800974 struct linux_efi_memreserve *rsv;
Ard Biesheuvel80424b02018-11-29 18:12:29 +0100975 unsigned long prsv;
976 int rc, index;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700977
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100978 if (efi_memreserve_root == (void *)ULONG_MAX)
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -0700979 return -ENODEV;
980
Ard Biesheuvel976b4892018-11-23 22:51:32 +0100981 if (!efi_memreserve_root) {
982 rc = efi_memreserve_map_root();
983 if (rc)
984 return rc;
985 }
986
Ard Biesheuvel80424b02018-11-29 18:12:29 +0100987 /* first try to find a slot in an existing linked list entry */
988 for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
Ard Biesheuvel18df7572019-06-09 20:17:44 +0200989 rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
Ard Biesheuvel80424b02018-11-29 18:12:29 +0100990 index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
991 if (index < rsv->size) {
992 rsv->entry[index].base = addr;
993 rsv->entry[index].size = size;
994
Ard Biesheuvel18df7572019-06-09 20:17:44 +0200995 memunmap(rsv);
Ard Biesheuvelab0eb162019-12-06 16:55:37 +0000996 return efi_mem_reserve_iomem(addr, size);
Ard Biesheuvel80424b02018-11-29 18:12:29 +0100997 }
Ard Biesheuvel18df7572019-06-09 20:17:44 +0200998 memunmap(rsv);
Ard Biesheuvel80424b02018-11-29 18:12:29 +0100999 }
1000
1001 /* no slot found - allocate a new linked list entry */
1002 rsv = (struct linux_efi_memreserve *)__get_free_page(GFP_ATOMIC);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001003 if (!rsv)
1004 return -ENOMEM;
1005
Ard Biesheuvelab0eb162019-12-06 16:55:37 +00001006 rc = efi_mem_reserve_iomem(__pa(rsv), SZ_4K);
1007 if (rc) {
1008 free_page((unsigned long)rsv);
1009 return rc;
1010 }
1011
Ard Biesheuvel18df7572019-06-09 20:17:44 +02001012 /*
1013 * The memremap() call above assumes that a linux_efi_memreserve entry
1014 * never crosses a page boundary, so let's ensure that this remains true
1015 * even when kexec'ing a 4k pages kernel from a >4k pages kernel, by
1016 * using SZ_4K explicitly in the size calculation below.
1017 */
1018 rsv->size = EFI_MEMRESERVE_COUNT(SZ_4K);
Ard Biesheuvel5f0b0ec2018-11-29 18:12:28 +01001019 atomic_set(&rsv->count, 1);
1020 rsv->entry[0].base = addr;
1021 rsv->entry[0].size = size;
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001022
1023 spin_lock(&efi_mem_reserve_persistent_lock);
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001024 rsv->next = efi_memreserve_root->next;
1025 efi_memreserve_root->next = __pa(rsv);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001026 spin_unlock(&efi_mem_reserve_persistent_lock);
1027
Ard Biesheuvelab0eb162019-12-06 16:55:37 +00001028 return efi_mem_reserve_iomem(addr, size);
Ard Biesheuvela23d3bb2018-09-21 09:32:46 -07001029}
1030
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001031static int __init efi_memreserve_root_init(void)
1032{
Ard Biesheuvel976b4892018-11-23 22:51:32 +01001033 if (efi_memreserve_root)
1034 return 0;
1035 if (efi_memreserve_map_root())
1036 efi_memreserve_root = (void *)ULONG_MAX;
Ard Biesheuvel63eb3222018-11-14 09:55:44 -08001037 return 0;
1038}
1039early_initcall(efi_memreserve_root_init);
1040
Ard Biesheuvel63625982016-11-12 21:32:31 +00001041#ifdef CONFIG_KEXEC
1042static int update_efi_random_seed(struct notifier_block *nb,
1043 unsigned long code, void *unused)
1044{
1045 struct linux_efi_random_seed *seed;
1046 u32 size = 0;
1047
1048 if (!kexec_in_progress)
1049 return NOTIFY_DONE;
1050
Ard Biesheuvel5d288db2020-01-22 14:58:15 +01001051 seed = memremap(rng_seed, sizeof(*seed), MEMREMAP_WB);
Ard Biesheuvel63625982016-11-12 21:32:31 +00001052 if (seed != NULL) {
Ard Biesheuvelc2ceb5f2017-08-25 16:50:16 +01001053 size = min(seed->size, EFI_RANDOM_SEED_SIZE);
Ard Biesheuvel63625982016-11-12 21:32:31 +00001054 memunmap(seed);
1055 } else {
1056 pr_err("Could not map UEFI random seed!\n");
1057 }
1058 if (size > 0) {
Ard Biesheuvel5d288db2020-01-22 14:58:15 +01001059 seed = memremap(rng_seed, sizeof(*seed) + size, MEMREMAP_WB);
Ard Biesheuvel63625982016-11-12 21:32:31 +00001060 if (seed != NULL) {
1061 seed->size = size;
1062 get_random_bytes(seed->bits, seed->size);
1063 memunmap(seed);
1064 } else {
1065 pr_err("Could not map UEFI random seed!\n");
1066 }
1067 }
1068 return NOTIFY_DONE;
1069}
1070
1071static struct notifier_block efi_random_seed_nb = {
1072 .notifier_call = update_efi_random_seed,
1073};
1074
Ard Biesheuvel5d288db2020-01-22 14:58:15 +01001075static int __init register_update_efi_random_seed(void)
Ard Biesheuvel63625982016-11-12 21:32:31 +00001076{
Ard Biesheuvel5d288db2020-01-22 14:58:15 +01001077 if (rng_seed == EFI_INVALID_TABLE_ADDR)
Ard Biesheuvel63625982016-11-12 21:32:31 +00001078 return 0;
1079 return register_reboot_notifier(&efi_random_seed_nb);
1080}
1081late_initcall(register_update_efi_random_seed);
1082#endif