162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * efi.c - EFI subsystem
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
662306a36Sopenharmony_ci * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
762306a36Sopenharmony_ci * Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This code registers /sys/firmware/efi{,/efivars} when EFI is supported,
1062306a36Sopenharmony_ci * allowing the efivarfs to be mounted or the efivars module to be loaded.
1162306a36Sopenharmony_ci * The existance of /sys/firmware/efi may also be used by userspace to
1262306a36Sopenharmony_ci * determine that the system supports EFI.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/kobject.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/init.h>
2062306a36Sopenharmony_ci#include <linux/debugfs.h>
2162306a36Sopenharmony_ci#include <linux/device.h>
2262306a36Sopenharmony_ci#include <linux/efi.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/initrd.h>
2562306a36Sopenharmony_ci#include <linux/io.h>
2662306a36Sopenharmony_ci#include <linux/kexec.h>
2762306a36Sopenharmony_ci#include <linux/platform_device.h>
2862306a36Sopenharmony_ci#include <linux/random.h>
2962306a36Sopenharmony_ci#include <linux/reboot.h>
3062306a36Sopenharmony_ci#include <linux/slab.h>
3162306a36Sopenharmony_ci#include <linux/acpi.h>
3262306a36Sopenharmony_ci#include <linux/ucs2_string.h>
3362306a36Sopenharmony_ci#include <linux/memblock.h>
3462306a36Sopenharmony_ci#include <linux/security.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <asm/early_ioremap.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistruct efi __read_mostly efi = {
3962306a36Sopenharmony_ci	.runtime_supported_mask = EFI_RT_SUPPORTED_ALL,
4062306a36Sopenharmony_ci	.acpi			= EFI_INVALID_TABLE_ADDR,
4162306a36Sopenharmony_ci	.acpi20			= EFI_INVALID_TABLE_ADDR,
4262306a36Sopenharmony_ci	.smbios			= EFI_INVALID_TABLE_ADDR,
4362306a36Sopenharmony_ci	.smbios3		= EFI_INVALID_TABLE_ADDR,
4462306a36Sopenharmony_ci	.esrt			= EFI_INVALID_TABLE_ADDR,
4562306a36Sopenharmony_ci	.tpm_log		= EFI_INVALID_TABLE_ADDR,
4662306a36Sopenharmony_ci	.tpm_final_log		= EFI_INVALID_TABLE_ADDR,
4762306a36Sopenharmony_ci#ifdef CONFIG_LOAD_UEFI_KEYS
4862306a36Sopenharmony_ci	.mokvar_table		= EFI_INVALID_TABLE_ADDR,
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci#ifdef CONFIG_EFI_COCO_SECRET
5162306a36Sopenharmony_ci	.coco_secret		= EFI_INVALID_TABLE_ADDR,
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_ci#ifdef CONFIG_UNACCEPTED_MEMORY
5462306a36Sopenharmony_ci	.unaccepted		= EFI_INVALID_TABLE_ADDR,
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ciEXPORT_SYMBOL(efi);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciunsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR;
6062306a36Sopenharmony_cistatic unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
6162306a36Sopenharmony_cistatic unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
6262306a36Sopenharmony_cistatic unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciextern unsigned long screen_info_table;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistruct mm_struct efi_mm = {
6762306a36Sopenharmony_ci	.mm_mt			= MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock),
6862306a36Sopenharmony_ci	.mm_users		= ATOMIC_INIT(2),
6962306a36Sopenharmony_ci	.mm_count		= ATOMIC_INIT(1),
7062306a36Sopenharmony_ci	.write_protect_seq      = SEQCNT_ZERO(efi_mm.write_protect_seq),
7162306a36Sopenharmony_ci	MMAP_LOCK_INITIALIZER(efi_mm)
7262306a36Sopenharmony_ci	.page_table_lock	= __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
7362306a36Sopenharmony_ci	.mmlist			= LIST_HEAD_INIT(efi_mm.mmlist),
7462306a36Sopenharmony_ci	.cpu_bitmap		= { [BITS_TO_LONGS(NR_CPUS)] = 0},
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct workqueue_struct *efi_rts_wq;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic bool disable_runtime = IS_ENABLED(CONFIG_EFI_DISABLE_RUNTIME);
8062306a36Sopenharmony_cistatic int __init setup_noefi(char *arg)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	disable_runtime = true;
8362306a36Sopenharmony_ci	return 0;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ciearly_param("noefi", setup_noefi);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cibool efi_runtime_disabled(void)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	return disable_runtime;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cibool __pure __efi_soft_reserve_enabled(void)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int __init parse_efi_cmdline(char *str)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (!str) {
10062306a36Sopenharmony_ci		pr_warn("need at least one option\n");
10162306a36Sopenharmony_ci		return -EINVAL;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (parse_option_str(str, "debug"))
10562306a36Sopenharmony_ci		set_bit(EFI_DBG, &efi.flags);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (parse_option_str(str, "noruntime"))
10862306a36Sopenharmony_ci		disable_runtime = true;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (parse_option_str(str, "runtime"))
11162306a36Sopenharmony_ci		disable_runtime = false;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (parse_option_str(str, "nosoftreserve"))
11462306a36Sopenharmony_ci		set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ciearly_param("efi", parse_efi_cmdline);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct kobject *efi_kobj;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * Let's not leave out systab information that snuck into
12462306a36Sopenharmony_ci * the efivars driver
12562306a36Sopenharmony_ci * Note, do not add more fields in systab sysfs file as it breaks sysfs
12662306a36Sopenharmony_ci * one value per file rule!
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_cistatic ssize_t systab_show(struct kobject *kobj,
12962306a36Sopenharmony_ci			   struct kobj_attribute *attr, char *buf)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	char *str = buf;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (!kobj || !buf)
13462306a36Sopenharmony_ci		return -EINVAL;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
13762306a36Sopenharmony_ci		str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
13862306a36Sopenharmony_ci	if (efi.acpi != EFI_INVALID_TABLE_ADDR)
13962306a36Sopenharmony_ci		str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
14062306a36Sopenharmony_ci	/*
14162306a36Sopenharmony_ci	 * If both SMBIOS and SMBIOS3 entry points are implemented, the
14262306a36Sopenharmony_ci	 * SMBIOS3 entry point shall be preferred, so we list it first to
14362306a36Sopenharmony_ci	 * let applications stop parsing after the first match.
14462306a36Sopenharmony_ci	 */
14562306a36Sopenharmony_ci	if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
14662306a36Sopenharmony_ci		str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
14762306a36Sopenharmony_ci	if (efi.smbios != EFI_INVALID_TABLE_ADDR)
14862306a36Sopenharmony_ci		str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86))
15162306a36Sopenharmony_ci		str = efi_systab_show_arch(str);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return str - buf;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic ssize_t fw_platform_size_show(struct kobject *kobj,
15962306a36Sopenharmony_ci				     struct kobj_attribute *attr, char *buf)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ciextern __weak struct kobj_attribute efi_attr_fw_vendor;
16562306a36Sopenharmony_ciextern __weak struct kobj_attribute efi_attr_runtime;
16662306a36Sopenharmony_ciextern __weak struct kobj_attribute efi_attr_config_table;
16762306a36Sopenharmony_cistatic struct kobj_attribute efi_attr_fw_platform_size =
16862306a36Sopenharmony_ci	__ATTR_RO(fw_platform_size);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic struct attribute *efi_subsys_attrs[] = {
17162306a36Sopenharmony_ci	&efi_attr_systab.attr,
17262306a36Sopenharmony_ci	&efi_attr_fw_platform_size.attr,
17362306a36Sopenharmony_ci	&efi_attr_fw_vendor.attr,
17462306a36Sopenharmony_ci	&efi_attr_runtime.attr,
17562306a36Sopenharmony_ci	&efi_attr_config_table.attr,
17662306a36Sopenharmony_ci	NULL,
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciumode_t __weak efi_attr_is_visible(struct kobject *kobj, struct attribute *attr,
18062306a36Sopenharmony_ci				   int n)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return attr->mode;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic const struct attribute_group efi_subsys_attr_group = {
18662306a36Sopenharmony_ci	.attrs = efi_subsys_attrs,
18762306a36Sopenharmony_ci	.is_visible = efi_attr_is_visible,
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic struct efivars generic_efivars;
19162306a36Sopenharmony_cistatic struct efivar_operations generic_ops;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic bool generic_ops_supported(void)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	unsigned long name_size;
19662306a36Sopenharmony_ci	efi_status_t status;
19762306a36Sopenharmony_ci	efi_char16_t name;
19862306a36Sopenharmony_ci	efi_guid_t guid;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	name_size = sizeof(name);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	status = efi.get_next_variable(&name_size, &name, &guid);
20362306a36Sopenharmony_ci	if (status == EFI_UNSUPPORTED)
20462306a36Sopenharmony_ci		return false;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return true;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int generic_ops_register(void)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	if (!generic_ops_supported())
21262306a36Sopenharmony_ci		return 0;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	generic_ops.get_variable = efi.get_variable;
21562306a36Sopenharmony_ci	generic_ops.get_next_variable = efi.get_next_variable;
21662306a36Sopenharmony_ci	generic_ops.query_variable_store = efi_query_variable_store;
21762306a36Sopenharmony_ci	generic_ops.query_variable_info = efi.query_variable_info;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE)) {
22062306a36Sopenharmony_ci		generic_ops.set_variable = efi.set_variable;
22162306a36Sopenharmony_ci		generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci	return efivars_register(&generic_efivars, &generic_ops);
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic void generic_ops_unregister(void)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	if (!generic_ops.get_variable)
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	efivars_unregister(&generic_efivars);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci#ifdef CONFIG_EFI_CUSTOM_SSDT_OVERLAYS
23562306a36Sopenharmony_ci#define EFIVAR_SSDT_NAME_MAX	16UL
23662306a36Sopenharmony_cistatic char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
23762306a36Sopenharmony_cistatic int __init efivar_ssdt_setup(char *str)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (ret)
24262306a36Sopenharmony_ci		return ret;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (strlen(str) < sizeof(efivar_ssdt))
24562306a36Sopenharmony_ci		memcpy(efivar_ssdt, str, strlen(str));
24662306a36Sopenharmony_ci	else
24762306a36Sopenharmony_ci		pr_warn("efivar_ssdt: name too long: %s\n", str);
24862306a36Sopenharmony_ci	return 1;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci__setup("efivar_ssdt=", efivar_ssdt_setup);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic __init int efivar_ssdt_load(void)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	unsigned long name_size = 256;
25562306a36Sopenharmony_ci	efi_char16_t *name = NULL;
25662306a36Sopenharmony_ci	efi_status_t status;
25762306a36Sopenharmony_ci	efi_guid_t guid;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (!efivar_ssdt[0])
26062306a36Sopenharmony_ci		return 0;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	name = kzalloc(name_size, GFP_KERNEL);
26362306a36Sopenharmony_ci	if (!name)
26462306a36Sopenharmony_ci		return -ENOMEM;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	for (;;) {
26762306a36Sopenharmony_ci		char utf8_name[EFIVAR_SSDT_NAME_MAX];
26862306a36Sopenharmony_ci		unsigned long data_size = 0;
26962306a36Sopenharmony_ci		void *data;
27062306a36Sopenharmony_ci		int limit;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		status = efi.get_next_variable(&name_size, name, &guid);
27362306a36Sopenharmony_ci		if (status == EFI_NOT_FOUND) {
27462306a36Sopenharmony_ci			break;
27562306a36Sopenharmony_ci		} else if (status == EFI_BUFFER_TOO_SMALL) {
27662306a36Sopenharmony_ci			efi_char16_t *name_tmp =
27762306a36Sopenharmony_ci				krealloc(name, name_size, GFP_KERNEL);
27862306a36Sopenharmony_ci			if (!name_tmp) {
27962306a36Sopenharmony_ci				kfree(name);
28062306a36Sopenharmony_ci				return -ENOMEM;
28162306a36Sopenharmony_ci			}
28262306a36Sopenharmony_ci			name = name_tmp;
28362306a36Sopenharmony_ci			continue;
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		limit = min(EFIVAR_SSDT_NAME_MAX, name_size);
28762306a36Sopenharmony_ci		ucs2_as_utf8(utf8_name, name, limit - 1);
28862306a36Sopenharmony_ci		if (strncmp(utf8_name, efivar_ssdt, limit) != 0)
28962306a36Sopenharmony_ci			continue;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt, &guid);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		status = efi.get_variable(name, &guid, NULL, &data_size, NULL);
29462306a36Sopenharmony_ci		if (status != EFI_BUFFER_TOO_SMALL || !data_size)
29562306a36Sopenharmony_ci			return -EIO;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		data = kmalloc(data_size, GFP_KERNEL);
29862306a36Sopenharmony_ci		if (!data)
29962306a36Sopenharmony_ci			return -ENOMEM;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		status = efi.get_variable(name, &guid, NULL, &data_size, data);
30262306a36Sopenharmony_ci		if (status == EFI_SUCCESS) {
30362306a36Sopenharmony_ci			acpi_status ret = acpi_load_table(data, NULL);
30462306a36Sopenharmony_ci			if (ret)
30562306a36Sopenharmony_ci				pr_err("failed to load table: %u\n", ret);
30662306a36Sopenharmony_ci			else
30762306a36Sopenharmony_ci				continue;
30862306a36Sopenharmony_ci		} else {
30962306a36Sopenharmony_ci			pr_err("failed to get var data: 0x%lx\n", status);
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci		kfree(data);
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	return 0;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci#else
31662306a36Sopenharmony_cistatic inline int efivar_ssdt_load(void) { return 0; }
31762306a36Sopenharmony_ci#endif
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci#define EFI_DEBUGFS_MAX_BLOBS 32
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS];
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic void __init efi_debugfs_init(void)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct dentry *efi_debugfs;
32862306a36Sopenharmony_ci	efi_memory_desc_t *md;
32962306a36Sopenharmony_ci	char name[32];
33062306a36Sopenharmony_ci	int type_count[EFI_BOOT_SERVICES_DATA + 1] = {};
33162306a36Sopenharmony_ci	int i = 0;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	efi_debugfs = debugfs_create_dir("efi", NULL);
33462306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(efi_debugfs))
33562306a36Sopenharmony_ci		return;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
33862306a36Sopenharmony_ci		switch (md->type) {
33962306a36Sopenharmony_ci		case EFI_BOOT_SERVICES_CODE:
34062306a36Sopenharmony_ci			snprintf(name, sizeof(name), "boot_services_code%d",
34162306a36Sopenharmony_ci				 type_count[md->type]++);
34262306a36Sopenharmony_ci			break;
34362306a36Sopenharmony_ci		case EFI_BOOT_SERVICES_DATA:
34462306a36Sopenharmony_ci			snprintf(name, sizeof(name), "boot_services_data%d",
34562306a36Sopenharmony_ci				 type_count[md->type]++);
34662306a36Sopenharmony_ci			break;
34762306a36Sopenharmony_ci		default:
34862306a36Sopenharmony_ci			continue;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		if (i >= EFI_DEBUGFS_MAX_BLOBS) {
35262306a36Sopenharmony_ci			pr_warn("More then %d EFI boot service segments, only showing first %d in debugfs\n",
35362306a36Sopenharmony_ci				EFI_DEBUGFS_MAX_BLOBS, EFI_DEBUGFS_MAX_BLOBS);
35462306a36Sopenharmony_ci			break;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT;
35862306a36Sopenharmony_ci		debugfs_blob[i].data = memremap(md->phys_addr,
35962306a36Sopenharmony_ci						debugfs_blob[i].size,
36062306a36Sopenharmony_ci						MEMREMAP_WB);
36162306a36Sopenharmony_ci		if (!debugfs_blob[i].data)
36262306a36Sopenharmony_ci			continue;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]);
36562306a36Sopenharmony_ci		i++;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci#else
36962306a36Sopenharmony_cistatic inline void efi_debugfs_init(void) {}
37062306a36Sopenharmony_ci#endif
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/*
37362306a36Sopenharmony_ci * We register the efi subsystem with the firmware subsystem and the
37462306a36Sopenharmony_ci * efivars subsystem with the efi subsystem, if the system was booted with
37562306a36Sopenharmony_ci * EFI.
37662306a36Sopenharmony_ci */
37762306a36Sopenharmony_cistatic int __init efisubsys_init(void)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	int error;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (!efi_enabled(EFI_RUNTIME_SERVICES))
38262306a36Sopenharmony_ci		efi.runtime_supported_mask = 0;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (!efi_enabled(EFI_BOOT))
38562306a36Sopenharmony_ci		return 0;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (efi.runtime_supported_mask) {
38862306a36Sopenharmony_ci		/*
38962306a36Sopenharmony_ci		 * Since we process only one efi_runtime_service() at a time, an
39062306a36Sopenharmony_ci		 * ordered workqueue (which creates only one execution context)
39162306a36Sopenharmony_ci		 * should suffice for all our needs.
39262306a36Sopenharmony_ci		 */
39362306a36Sopenharmony_ci		efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
39462306a36Sopenharmony_ci		if (!efi_rts_wq) {
39562306a36Sopenharmony_ci			pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
39662306a36Sopenharmony_ci			clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
39762306a36Sopenharmony_ci			efi.runtime_supported_mask = 0;
39862306a36Sopenharmony_ci			return 0;
39962306a36Sopenharmony_ci		}
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (efi_rt_services_supported(EFI_RT_SUPPORTED_TIME_SERVICES))
40362306a36Sopenharmony_ci		platform_device_register_simple("rtc-efi", 0, NULL, 0);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* We register the efi directory at /sys/firmware/efi */
40662306a36Sopenharmony_ci	efi_kobj = kobject_create_and_add("efi", firmware_kobj);
40762306a36Sopenharmony_ci	if (!efi_kobj) {
40862306a36Sopenharmony_ci		pr_err("efi: Firmware registration failed.\n");
40962306a36Sopenharmony_ci		error = -ENOMEM;
41062306a36Sopenharmony_ci		goto err_destroy_wq;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
41462306a36Sopenharmony_ci				      EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME)) {
41562306a36Sopenharmony_ci		error = generic_ops_register();
41662306a36Sopenharmony_ci		if (error)
41762306a36Sopenharmony_ci			goto err_put;
41862306a36Sopenharmony_ci		efivar_ssdt_load();
41962306a36Sopenharmony_ci		platform_device_register_simple("efivars", 0, NULL, 0);
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
42362306a36Sopenharmony_ci	if (error) {
42462306a36Sopenharmony_ci		pr_err("efi: Sysfs attribute export failed with error %d.\n",
42562306a36Sopenharmony_ci		       error);
42662306a36Sopenharmony_ci		goto err_unregister;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* and the standard mountpoint for efivarfs */
43062306a36Sopenharmony_ci	error = sysfs_create_mount_point(efi_kobj, "efivars");
43162306a36Sopenharmony_ci	if (error) {
43262306a36Sopenharmony_ci		pr_err("efivars: Subsystem registration failed.\n");
43362306a36Sopenharmony_ci		goto err_remove_group;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (efi_enabled(EFI_DBG) && efi_enabled(EFI_PRESERVE_BS_REGIONS))
43762306a36Sopenharmony_ci		efi_debugfs_init();
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci#ifdef CONFIG_EFI_COCO_SECRET
44062306a36Sopenharmony_ci	if (efi.coco_secret != EFI_INVALID_TABLE_ADDR)
44162306a36Sopenharmony_ci		platform_device_register_simple("efi_secret", 0, NULL, 0);
44262306a36Sopenharmony_ci#endif
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return 0;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cierr_remove_group:
44762306a36Sopenharmony_ci	sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
44862306a36Sopenharmony_cierr_unregister:
44962306a36Sopenharmony_ci	if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
45062306a36Sopenharmony_ci				      EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME))
45162306a36Sopenharmony_ci		generic_ops_unregister();
45262306a36Sopenharmony_cierr_put:
45362306a36Sopenharmony_ci	kobject_put(efi_kobj);
45462306a36Sopenharmony_ci	efi_kobj = NULL;
45562306a36Sopenharmony_cierr_destroy_wq:
45662306a36Sopenharmony_ci	if (efi_rts_wq)
45762306a36Sopenharmony_ci		destroy_workqueue(efi_rts_wq);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return error;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cisubsys_initcall(efisubsys_init);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_civoid __init efi_find_mirror(void)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	efi_memory_desc_t *md;
46762306a36Sopenharmony_ci	u64 mirror_size = 0, total_size = 0;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (!efi_enabled(EFI_MEMMAP))
47062306a36Sopenharmony_ci		return;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
47362306a36Sopenharmony_ci		unsigned long long start = md->phys_addr;
47462306a36Sopenharmony_ci		unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		total_size += size;
47762306a36Sopenharmony_ci		if (md->attribute & EFI_MEMORY_MORE_RELIABLE) {
47862306a36Sopenharmony_ci			memblock_mark_mirror(start, size);
47962306a36Sopenharmony_ci			mirror_size += size;
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci	if (mirror_size)
48362306a36Sopenharmony_ci		pr_info("Memory: %lldM/%lldM mirrored memory\n",
48462306a36Sopenharmony_ci			mirror_size>>20, total_size>>20);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/*
48862306a36Sopenharmony_ci * Find the efi memory descriptor for a given physical address.  Given a
48962306a36Sopenharmony_ci * physical address, determine if it exists within an EFI Memory Map entry,
49062306a36Sopenharmony_ci * and if so, populate the supplied memory descriptor with the appropriate
49162306a36Sopenharmony_ci * data.
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_ciint __efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	efi_memory_desc_t *md;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (!efi_enabled(EFI_MEMMAP)) {
49862306a36Sopenharmony_ci		pr_err_once("EFI_MEMMAP is not enabled.\n");
49962306a36Sopenharmony_ci		return -EINVAL;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (!out_md) {
50362306a36Sopenharmony_ci		pr_err_once("out_md is null.\n");
50462306a36Sopenharmony_ci		return -EINVAL;
50562306a36Sopenharmony_ci        }
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
50862306a36Sopenharmony_ci		u64 size;
50962306a36Sopenharmony_ci		u64 end;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		/* skip bogus entries (including empty ones) */
51262306a36Sopenharmony_ci		if ((md->phys_addr & (EFI_PAGE_SIZE - 1)) ||
51362306a36Sopenharmony_ci		    (md->num_pages <= 0) ||
51462306a36Sopenharmony_ci		    (md->num_pages > (U64_MAX - md->phys_addr) >> EFI_PAGE_SHIFT))
51562306a36Sopenharmony_ci			continue;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		size = md->num_pages << EFI_PAGE_SHIFT;
51862306a36Sopenharmony_ci		end = md->phys_addr + size;
51962306a36Sopenharmony_ci		if (phys_addr >= md->phys_addr && phys_addr < end) {
52062306a36Sopenharmony_ci			memcpy(out_md, md, sizeof(*out_md));
52162306a36Sopenharmony_ci			return 0;
52262306a36Sopenharmony_ci		}
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci	return -ENOENT;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ciextern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
52862306a36Sopenharmony_ci	__weak __alias(__efi_mem_desc_lookup);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/*
53162306a36Sopenharmony_ci * Calculate the highest address of an efi memory descriptor.
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_ciu64 __init efi_mem_desc_end(efi_memory_desc_t *md)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	u64 size = md->num_pages << EFI_PAGE_SHIFT;
53662306a36Sopenharmony_ci	u64 end = md->phys_addr + size;
53762306a36Sopenharmony_ci	return end;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_civoid __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci/**
54362306a36Sopenharmony_ci * efi_mem_reserve - Reserve an EFI memory region
54462306a36Sopenharmony_ci * @addr: Physical address to reserve
54562306a36Sopenharmony_ci * @size: Size of reservation
54662306a36Sopenharmony_ci *
54762306a36Sopenharmony_ci * Mark a region as reserved from general kernel allocation and
54862306a36Sopenharmony_ci * prevent it being released by efi_free_boot_services().
54962306a36Sopenharmony_ci *
55062306a36Sopenharmony_ci * This function should be called drivers once they've parsed EFI
55162306a36Sopenharmony_ci * configuration tables to figure out where their data lives, e.g.
55262306a36Sopenharmony_ci * efi_esrt_init().
55362306a36Sopenharmony_ci */
55462306a36Sopenharmony_civoid __init efi_mem_reserve(phys_addr_t addr, u64 size)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	/* efi_mem_reserve() does not work under Xen */
55762306a36Sopenharmony_ci	if (WARN_ON_ONCE(efi_enabled(EFI_PARAVIRT)))
55862306a36Sopenharmony_ci		return;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (!memblock_is_region_reserved(addr, size))
56162306a36Sopenharmony_ci		memblock_reserve(addr, size);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/*
56462306a36Sopenharmony_ci	 * Some architectures (x86) reserve all boot services ranges
56562306a36Sopenharmony_ci	 * until efi_free_boot_services() because of buggy firmware
56662306a36Sopenharmony_ci	 * implementations. This means the above memblock_reserve() is
56762306a36Sopenharmony_ci	 * superfluous on x86 and instead what it needs to do is
56862306a36Sopenharmony_ci	 * ensure the @start, @size is not freed.
56962306a36Sopenharmony_ci	 */
57062306a36Sopenharmony_ci	efi_arch_mem_reserve(addr, size);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic const efi_config_table_type_t common_tables[] __initconst = {
57462306a36Sopenharmony_ci	{ACPI_20_TABLE_GUID,			&efi.acpi20,		"ACPI 2.0"	},
57562306a36Sopenharmony_ci	{ACPI_TABLE_GUID,			&efi.acpi,		"ACPI"		},
57662306a36Sopenharmony_ci	{SMBIOS_TABLE_GUID,			&efi.smbios,		"SMBIOS"	},
57762306a36Sopenharmony_ci	{SMBIOS3_TABLE_GUID,			&efi.smbios3,		"SMBIOS 3.0"	},
57862306a36Sopenharmony_ci	{EFI_SYSTEM_RESOURCE_TABLE_GUID,	&efi.esrt,		"ESRT"		},
57962306a36Sopenharmony_ci	{EFI_MEMORY_ATTRIBUTES_TABLE_GUID,	&efi_mem_attr_table,	"MEMATTR"	},
58062306a36Sopenharmony_ci	{LINUX_EFI_RANDOM_SEED_TABLE_GUID,	&efi_rng_seed,		"RNG"		},
58162306a36Sopenharmony_ci	{LINUX_EFI_TPM_EVENT_LOG_GUID,		&efi.tpm_log,		"TPMEventLog"	},
58262306a36Sopenharmony_ci	{LINUX_EFI_TPM_FINAL_LOG_GUID,		&efi.tpm_final_log,	"TPMFinalLog"	},
58362306a36Sopenharmony_ci	{LINUX_EFI_MEMRESERVE_TABLE_GUID,	&mem_reserve,		"MEMRESERVE"	},
58462306a36Sopenharmony_ci	{LINUX_EFI_INITRD_MEDIA_GUID,		&initrd,		"INITRD"	},
58562306a36Sopenharmony_ci	{EFI_RT_PROPERTIES_TABLE_GUID,		&rt_prop,		"RTPROP"	},
58662306a36Sopenharmony_ci#ifdef CONFIG_EFI_RCI2_TABLE
58762306a36Sopenharmony_ci	{DELLEMC_EFI_RCI2_TABLE_GUID,		&rci2_table_phys			},
58862306a36Sopenharmony_ci#endif
58962306a36Sopenharmony_ci#ifdef CONFIG_LOAD_UEFI_KEYS
59062306a36Sopenharmony_ci	{LINUX_EFI_MOK_VARIABLE_TABLE_GUID,	&efi.mokvar_table,	"MOKvar"	},
59162306a36Sopenharmony_ci#endif
59262306a36Sopenharmony_ci#ifdef CONFIG_EFI_COCO_SECRET
59362306a36Sopenharmony_ci	{LINUX_EFI_COCO_SECRET_AREA_GUID,	&efi.coco_secret,	"CocoSecret"	},
59462306a36Sopenharmony_ci#endif
59562306a36Sopenharmony_ci#ifdef CONFIG_UNACCEPTED_MEMORY
59662306a36Sopenharmony_ci	{LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID,	&efi.unaccepted,	"Unaccepted"	},
59762306a36Sopenharmony_ci#endif
59862306a36Sopenharmony_ci#ifdef CONFIG_EFI_GENERIC_STUB
59962306a36Sopenharmony_ci	{LINUX_EFI_SCREEN_INFO_TABLE_GUID,	&screen_info_table			},
60062306a36Sopenharmony_ci#endif
60162306a36Sopenharmony_ci	{},
60262306a36Sopenharmony_ci};
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic __init int match_config_table(const efi_guid_t *guid,
60562306a36Sopenharmony_ci				     unsigned long table,
60662306a36Sopenharmony_ci				     const efi_config_table_type_t *table_types)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	int i;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
61162306a36Sopenharmony_ci		if (efi_guidcmp(*guid, table_types[i].guid))
61262306a36Sopenharmony_ci			continue;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		if (!efi_config_table_is_usable(guid, table)) {
61562306a36Sopenharmony_ci			if (table_types[i].name[0])
61662306a36Sopenharmony_ci				pr_cont("(%s=0x%lx unusable) ",
61762306a36Sopenharmony_ci					table_types[i].name, table);
61862306a36Sopenharmony_ci			return 1;
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		*(table_types[i].ptr) = table;
62262306a36Sopenharmony_ci		if (table_types[i].name[0])
62362306a36Sopenharmony_ci			pr_cont("%s=0x%lx ", table_types[i].name, table);
62462306a36Sopenharmony_ci		return 1;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return 0;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci/**
63162306a36Sopenharmony_ci * reserve_unaccepted - Map and reserve unaccepted configuration table
63262306a36Sopenharmony_ci * @unaccepted: Pointer to unaccepted memory table
63362306a36Sopenharmony_ci *
63462306a36Sopenharmony_ci * memblock_add() makes sure that the table is mapped in direct mapping. During
63562306a36Sopenharmony_ci * normal boot it happens automatically because the table is allocated from
63662306a36Sopenharmony_ci * usable memory. But during crashkernel boot only memory specifically reserved
63762306a36Sopenharmony_ci * for crash scenario is mapped. memblock_add() forces the table to be mapped
63862306a36Sopenharmony_ci * in crashkernel case.
63962306a36Sopenharmony_ci *
64062306a36Sopenharmony_ci * Align the range to the nearest page borders. Ranges smaller than page size
64162306a36Sopenharmony_ci * are not going to be mapped.
64262306a36Sopenharmony_ci *
64362306a36Sopenharmony_ci * memblock_reserve() makes sure that future allocations will not touch the
64462306a36Sopenharmony_ci * table.
64562306a36Sopenharmony_ci */
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic __init void reserve_unaccepted(struct efi_unaccepted_memory *unaccepted)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	phys_addr_t start, size;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	start = PAGE_ALIGN_DOWN(efi.unaccepted);
65262306a36Sopenharmony_ci	size = PAGE_ALIGN(sizeof(*unaccepted) + unaccepted->size);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	memblock_add(start, size);
65562306a36Sopenharmony_ci	memblock_reserve(start, size);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ciint __init efi_config_parse_tables(const efi_config_table_t *config_tables,
65962306a36Sopenharmony_ci				   int count,
66062306a36Sopenharmony_ci				   const efi_config_table_type_t *arch_tables)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	const efi_config_table_64_t *tbl64 = (void *)config_tables;
66362306a36Sopenharmony_ci	const efi_config_table_32_t *tbl32 = (void *)config_tables;
66462306a36Sopenharmony_ci	const efi_guid_t *guid;
66562306a36Sopenharmony_ci	unsigned long table;
66662306a36Sopenharmony_ci	int i;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	pr_info("");
66962306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
67062306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_X86)) {
67162306a36Sopenharmony_ci			guid = &config_tables[i].guid;
67262306a36Sopenharmony_ci			table = (unsigned long)config_tables[i].table;
67362306a36Sopenharmony_ci		} else if (efi_enabled(EFI_64BIT)) {
67462306a36Sopenharmony_ci			guid = &tbl64[i].guid;
67562306a36Sopenharmony_ci			table = tbl64[i].table;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci			if (IS_ENABLED(CONFIG_X86_32) &&
67862306a36Sopenharmony_ci			    tbl64[i].table > U32_MAX) {
67962306a36Sopenharmony_ci				pr_cont("\n");
68062306a36Sopenharmony_ci				pr_err("Table located above 4GB, disabling EFI.\n");
68162306a36Sopenharmony_ci				return -EINVAL;
68262306a36Sopenharmony_ci			}
68362306a36Sopenharmony_ci		} else {
68462306a36Sopenharmony_ci			guid = &tbl32[i].guid;
68562306a36Sopenharmony_ci			table = tbl32[i].table;
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		if (!match_config_table(guid, table, common_tables) && arch_tables)
68962306a36Sopenharmony_ci			match_config_table(guid, table, arch_tables);
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci	pr_cont("\n");
69262306a36Sopenharmony_ci	set_bit(EFI_CONFIG_TABLES, &efi.flags);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	if (efi_rng_seed != EFI_INVALID_TABLE_ADDR) {
69562306a36Sopenharmony_ci		struct linux_efi_random_seed *seed;
69662306a36Sopenharmony_ci		u32 size = 0;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		seed = early_memremap(efi_rng_seed, sizeof(*seed));
69962306a36Sopenharmony_ci		if (seed != NULL) {
70062306a36Sopenharmony_ci			size = min_t(u32, seed->size, SZ_1K); // sanity check
70162306a36Sopenharmony_ci			early_memunmap(seed, sizeof(*seed));
70262306a36Sopenharmony_ci		} else {
70362306a36Sopenharmony_ci			pr_err("Could not map UEFI random seed!\n");
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci		if (size > 0) {
70662306a36Sopenharmony_ci			seed = early_memremap(efi_rng_seed,
70762306a36Sopenharmony_ci					      sizeof(*seed) + size);
70862306a36Sopenharmony_ci			if (seed != NULL) {
70962306a36Sopenharmony_ci				add_bootloader_randomness(seed->bits, size);
71062306a36Sopenharmony_ci				memzero_explicit(seed->bits, size);
71162306a36Sopenharmony_ci				early_memunmap(seed, sizeof(*seed) + size);
71262306a36Sopenharmony_ci			} else {
71362306a36Sopenharmony_ci				pr_err("Could not map UEFI random seed!\n");
71462306a36Sopenharmony_ci			}
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_X86_32) && efi_enabled(EFI_MEMMAP))
71962306a36Sopenharmony_ci		efi_memattr_init();
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	efi_tpm_eventlog_init();
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (mem_reserve != EFI_INVALID_TABLE_ADDR) {
72462306a36Sopenharmony_ci		unsigned long prsv = mem_reserve;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		while (prsv) {
72762306a36Sopenharmony_ci			struct linux_efi_memreserve *rsv;
72862306a36Sopenharmony_ci			u8 *p;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci			/*
73162306a36Sopenharmony_ci			 * Just map a full page: that is what we will get
73262306a36Sopenharmony_ci			 * anyway, and it permits us to map the entire entry
73362306a36Sopenharmony_ci			 * before knowing its size.
73462306a36Sopenharmony_ci			 */
73562306a36Sopenharmony_ci			p = early_memremap(ALIGN_DOWN(prsv, PAGE_SIZE),
73662306a36Sopenharmony_ci					   PAGE_SIZE);
73762306a36Sopenharmony_ci			if (p == NULL) {
73862306a36Sopenharmony_ci				pr_err("Could not map UEFI memreserve entry!\n");
73962306a36Sopenharmony_ci				return -ENOMEM;
74062306a36Sopenharmony_ci			}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci			rsv = (void *)(p + prsv % PAGE_SIZE);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci			/* reserve the entry itself */
74562306a36Sopenharmony_ci			memblock_reserve(prsv,
74662306a36Sopenharmony_ci					 struct_size(rsv, entry, rsv->size));
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci			for (i = 0; i < atomic_read(&rsv->count); i++) {
74962306a36Sopenharmony_ci				memblock_reserve(rsv->entry[i].base,
75062306a36Sopenharmony_ci						 rsv->entry[i].size);
75162306a36Sopenharmony_ci			}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci			prsv = rsv->next;
75462306a36Sopenharmony_ci			early_memunmap(p, PAGE_SIZE);
75562306a36Sopenharmony_ci		}
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (rt_prop != EFI_INVALID_TABLE_ADDR) {
75962306a36Sopenharmony_ci		efi_rt_properties_table_t *tbl;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		tbl = early_memremap(rt_prop, sizeof(*tbl));
76262306a36Sopenharmony_ci		if (tbl) {
76362306a36Sopenharmony_ci			efi.runtime_supported_mask &= tbl->runtime_services_supported;
76462306a36Sopenharmony_ci			early_memunmap(tbl, sizeof(*tbl));
76562306a36Sopenharmony_ci		}
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) &&
76962306a36Sopenharmony_ci	    initrd != EFI_INVALID_TABLE_ADDR && phys_initrd_size == 0) {
77062306a36Sopenharmony_ci		struct linux_efi_initrd *tbl;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		tbl = early_memremap(initrd, sizeof(*tbl));
77362306a36Sopenharmony_ci		if (tbl) {
77462306a36Sopenharmony_ci			phys_initrd_start = tbl->base;
77562306a36Sopenharmony_ci			phys_initrd_size = tbl->size;
77662306a36Sopenharmony_ci			early_memunmap(tbl, sizeof(*tbl));
77762306a36Sopenharmony_ci		}
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_UNACCEPTED_MEMORY) &&
78162306a36Sopenharmony_ci	    efi.unaccepted != EFI_INVALID_TABLE_ADDR) {
78262306a36Sopenharmony_ci		struct efi_unaccepted_memory *unaccepted;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci		unaccepted = early_memremap(efi.unaccepted, sizeof(*unaccepted));
78562306a36Sopenharmony_ci		if (unaccepted) {
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci			if (unaccepted->version == 1) {
78862306a36Sopenharmony_ci				reserve_unaccepted(unaccepted);
78962306a36Sopenharmony_ci			} else {
79062306a36Sopenharmony_ci				efi.unaccepted = EFI_INVALID_TABLE_ADDR;
79162306a36Sopenharmony_ci			}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci			early_memunmap(unaccepted, sizeof(*unaccepted));
79462306a36Sopenharmony_ci		}
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return 0;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ciint __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	if (systab_hdr->signature != EFI_SYSTEM_TABLE_SIGNATURE) {
80362306a36Sopenharmony_ci		pr_err("System table signature incorrect!\n");
80462306a36Sopenharmony_ci		return -EINVAL;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	return 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci#ifndef CONFIG_IA64
81162306a36Sopenharmony_cistatic const efi_char16_t *__init map_fw_vendor(unsigned long fw_vendor,
81262306a36Sopenharmony_ci						size_t size)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	const efi_char16_t *ret;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	ret = early_memremap_ro(fw_vendor, size);
81762306a36Sopenharmony_ci	if (!ret)
81862306a36Sopenharmony_ci		pr_err("Could not map the firmware vendor!\n");
81962306a36Sopenharmony_ci	return ret;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic void __init unmap_fw_vendor(const void *fw_vendor, size_t size)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	early_memunmap((void *)fw_vendor, size);
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci#else
82762306a36Sopenharmony_ci#define map_fw_vendor(p, s)	__va(p)
82862306a36Sopenharmony_ci#define unmap_fw_vendor(v, s)
82962306a36Sopenharmony_ci#endif
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_civoid __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
83262306a36Sopenharmony_ci				     unsigned long fw_vendor)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	char vendor[100] = "unknown";
83562306a36Sopenharmony_ci	const efi_char16_t *c16;
83662306a36Sopenharmony_ci	size_t i;
83762306a36Sopenharmony_ci	u16 rev;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	c16 = map_fw_vendor(fw_vendor, sizeof(vendor) * sizeof(efi_char16_t));
84062306a36Sopenharmony_ci	if (c16) {
84162306a36Sopenharmony_ci		for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
84262306a36Sopenharmony_ci			vendor[i] = c16[i];
84362306a36Sopenharmony_ci		vendor[i] = '\0';
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci		unmap_fw_vendor(c16, sizeof(vendor) * sizeof(efi_char16_t));
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	rev = (u16)systab_hdr->revision;
84962306a36Sopenharmony_ci	pr_info("EFI v%u.%u", systab_hdr->revision >> 16, rev / 10);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	rev %= 10;
85262306a36Sopenharmony_ci	if (rev)
85362306a36Sopenharmony_ci		pr_cont(".%u", rev);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	pr_cont(" by %s\n", vendor);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_X86_64) &&
85862306a36Sopenharmony_ci	    systab_hdr->revision > EFI_1_10_SYSTEM_TABLE_REVISION &&
85962306a36Sopenharmony_ci	    !strcmp(vendor, "Apple")) {
86062306a36Sopenharmony_ci		pr_info("Apple Mac detected, using EFI v1.10 runtime services only\n");
86162306a36Sopenharmony_ci		efi.runtime_version = EFI_1_10_SYSTEM_TABLE_REVISION;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cistatic __initdata char memory_type_name[][13] = {
86662306a36Sopenharmony_ci	"Reserved",
86762306a36Sopenharmony_ci	"Loader Code",
86862306a36Sopenharmony_ci	"Loader Data",
86962306a36Sopenharmony_ci	"Boot Code",
87062306a36Sopenharmony_ci	"Boot Data",
87162306a36Sopenharmony_ci	"Runtime Code",
87262306a36Sopenharmony_ci	"Runtime Data",
87362306a36Sopenharmony_ci	"Conventional",
87462306a36Sopenharmony_ci	"Unusable",
87562306a36Sopenharmony_ci	"ACPI Reclaim",
87662306a36Sopenharmony_ci	"ACPI Mem NVS",
87762306a36Sopenharmony_ci	"MMIO",
87862306a36Sopenharmony_ci	"MMIO Port",
87962306a36Sopenharmony_ci	"PAL Code",
88062306a36Sopenharmony_ci	"Persistent",
88162306a36Sopenharmony_ci	"Unaccepted",
88262306a36Sopenharmony_ci};
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cichar * __init efi_md_typeattr_format(char *buf, size_t size,
88562306a36Sopenharmony_ci				     const efi_memory_desc_t *md)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	char *pos;
88862306a36Sopenharmony_ci	int type_len;
88962306a36Sopenharmony_ci	u64 attr;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	pos = buf;
89262306a36Sopenharmony_ci	if (md->type >= ARRAY_SIZE(memory_type_name))
89362306a36Sopenharmony_ci		type_len = snprintf(pos, size, "[type=%u", md->type);
89462306a36Sopenharmony_ci	else
89562306a36Sopenharmony_ci		type_len = snprintf(pos, size, "[%-*s",
89662306a36Sopenharmony_ci				    (int)(sizeof(memory_type_name[0]) - 1),
89762306a36Sopenharmony_ci				    memory_type_name[md->type]);
89862306a36Sopenharmony_ci	if (type_len >= size)
89962306a36Sopenharmony_ci		return buf;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	pos += type_len;
90262306a36Sopenharmony_ci	size -= type_len;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	attr = md->attribute;
90562306a36Sopenharmony_ci	if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
90662306a36Sopenharmony_ci		     EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
90762306a36Sopenharmony_ci		     EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
90862306a36Sopenharmony_ci		     EFI_MEMORY_NV | EFI_MEMORY_SP | EFI_MEMORY_CPU_CRYPTO |
90962306a36Sopenharmony_ci		     EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
91062306a36Sopenharmony_ci		snprintf(pos, size, "|attr=0x%016llx]",
91162306a36Sopenharmony_ci			 (unsigned long long)attr);
91262306a36Sopenharmony_ci	else
91362306a36Sopenharmony_ci		snprintf(pos, size,
91462306a36Sopenharmony_ci			 "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
91562306a36Sopenharmony_ci			 attr & EFI_MEMORY_RUNTIME		? "RUN" : "",
91662306a36Sopenharmony_ci			 attr & EFI_MEMORY_MORE_RELIABLE	? "MR"  : "",
91762306a36Sopenharmony_ci			 attr & EFI_MEMORY_CPU_CRYPTO   	? "CC"  : "",
91862306a36Sopenharmony_ci			 attr & EFI_MEMORY_SP			? "SP"  : "",
91962306a36Sopenharmony_ci			 attr & EFI_MEMORY_NV			? "NV"  : "",
92062306a36Sopenharmony_ci			 attr & EFI_MEMORY_XP			? "XP"  : "",
92162306a36Sopenharmony_ci			 attr & EFI_MEMORY_RP			? "RP"  : "",
92262306a36Sopenharmony_ci			 attr & EFI_MEMORY_WP			? "WP"  : "",
92362306a36Sopenharmony_ci			 attr & EFI_MEMORY_RO			? "RO"  : "",
92462306a36Sopenharmony_ci			 attr & EFI_MEMORY_UCE			? "UCE" : "",
92562306a36Sopenharmony_ci			 attr & EFI_MEMORY_WB			? "WB"  : "",
92662306a36Sopenharmony_ci			 attr & EFI_MEMORY_WT			? "WT"  : "",
92762306a36Sopenharmony_ci			 attr & EFI_MEMORY_WC			? "WC"  : "",
92862306a36Sopenharmony_ci			 attr & EFI_MEMORY_UC			? "UC"  : "");
92962306a36Sopenharmony_ci	return buf;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/*
93362306a36Sopenharmony_ci * IA64 has a funky EFI memory map that doesn't work the same way as
93462306a36Sopenharmony_ci * other architectures.
93562306a36Sopenharmony_ci */
93662306a36Sopenharmony_ci#ifndef CONFIG_IA64
93762306a36Sopenharmony_ci/*
93862306a36Sopenharmony_ci * efi_mem_attributes - lookup memmap attributes for physical address
93962306a36Sopenharmony_ci * @phys_addr: the physical address to lookup
94062306a36Sopenharmony_ci *
94162306a36Sopenharmony_ci * Search in the EFI memory map for the region covering
94262306a36Sopenharmony_ci * @phys_addr. Returns the EFI memory attributes if the region
94362306a36Sopenharmony_ci * was found in the memory map, 0 otherwise.
94462306a36Sopenharmony_ci */
94562306a36Sopenharmony_ciu64 efi_mem_attributes(unsigned long phys_addr)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	efi_memory_desc_t *md;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	if (!efi_enabled(EFI_MEMMAP))
95062306a36Sopenharmony_ci		return 0;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
95362306a36Sopenharmony_ci		if ((md->phys_addr <= phys_addr) &&
95462306a36Sopenharmony_ci		    (phys_addr < (md->phys_addr +
95562306a36Sopenharmony_ci		    (md->num_pages << EFI_PAGE_SHIFT))))
95662306a36Sopenharmony_ci			return md->attribute;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci	return 0;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci/*
96262306a36Sopenharmony_ci * efi_mem_type - lookup memmap type for physical address
96362306a36Sopenharmony_ci * @phys_addr: the physical address to lookup
96462306a36Sopenharmony_ci *
96562306a36Sopenharmony_ci * Search in the EFI memory map for the region covering @phys_addr.
96662306a36Sopenharmony_ci * Returns the EFI memory type if the region was found in the memory
96762306a36Sopenharmony_ci * map, -EINVAL otherwise.
96862306a36Sopenharmony_ci */
96962306a36Sopenharmony_ciint efi_mem_type(unsigned long phys_addr)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	const efi_memory_desc_t *md;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (!efi_enabled(EFI_MEMMAP))
97462306a36Sopenharmony_ci		return -ENOTSUPP;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
97762306a36Sopenharmony_ci		if ((md->phys_addr <= phys_addr) &&
97862306a36Sopenharmony_ci		    (phys_addr < (md->phys_addr +
97962306a36Sopenharmony_ci				  (md->num_pages << EFI_PAGE_SHIFT))))
98062306a36Sopenharmony_ci			return md->type;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci	return -EINVAL;
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci#endif
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ciint efi_status_to_err(efi_status_t status)
98762306a36Sopenharmony_ci{
98862306a36Sopenharmony_ci	int err;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	switch (status) {
99162306a36Sopenharmony_ci	case EFI_SUCCESS:
99262306a36Sopenharmony_ci		err = 0;
99362306a36Sopenharmony_ci		break;
99462306a36Sopenharmony_ci	case EFI_INVALID_PARAMETER:
99562306a36Sopenharmony_ci		err = -EINVAL;
99662306a36Sopenharmony_ci		break;
99762306a36Sopenharmony_ci	case EFI_OUT_OF_RESOURCES:
99862306a36Sopenharmony_ci		err = -ENOSPC;
99962306a36Sopenharmony_ci		break;
100062306a36Sopenharmony_ci	case EFI_DEVICE_ERROR:
100162306a36Sopenharmony_ci		err = -EIO;
100262306a36Sopenharmony_ci		break;
100362306a36Sopenharmony_ci	case EFI_WRITE_PROTECTED:
100462306a36Sopenharmony_ci		err = -EROFS;
100562306a36Sopenharmony_ci		break;
100662306a36Sopenharmony_ci	case EFI_SECURITY_VIOLATION:
100762306a36Sopenharmony_ci		err = -EACCES;
100862306a36Sopenharmony_ci		break;
100962306a36Sopenharmony_ci	case EFI_NOT_FOUND:
101062306a36Sopenharmony_ci		err = -ENOENT;
101162306a36Sopenharmony_ci		break;
101262306a36Sopenharmony_ci	case EFI_ABORTED:
101362306a36Sopenharmony_ci		err = -EINTR;
101462306a36Sopenharmony_ci		break;
101562306a36Sopenharmony_ci	default:
101662306a36Sopenharmony_ci		err = -EINVAL;
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	return err;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(efi_status_to_err);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistatic DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
102462306a36Sopenharmony_cistatic struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cistatic int __init efi_memreserve_map_root(void)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	if (mem_reserve == EFI_INVALID_TABLE_ADDR)
102962306a36Sopenharmony_ci		return -ENODEV;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	efi_memreserve_root = memremap(mem_reserve,
103262306a36Sopenharmony_ci				       sizeof(*efi_memreserve_root),
103362306a36Sopenharmony_ci				       MEMREMAP_WB);
103462306a36Sopenharmony_ci	if (WARN_ON_ONCE(!efi_memreserve_root))
103562306a36Sopenharmony_ci		return -ENOMEM;
103662306a36Sopenharmony_ci	return 0;
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic int efi_mem_reserve_iomem(phys_addr_t addr, u64 size)
104062306a36Sopenharmony_ci{
104162306a36Sopenharmony_ci	struct resource *res, *parent;
104262306a36Sopenharmony_ci	int ret;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
104562306a36Sopenharmony_ci	if (!res)
104662306a36Sopenharmony_ci		return -ENOMEM;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	res->name	= "reserved";
104962306a36Sopenharmony_ci	res->flags	= IORESOURCE_MEM;
105062306a36Sopenharmony_ci	res->start	= addr;
105162306a36Sopenharmony_ci	res->end	= addr + size - 1;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* we expect a conflict with a 'System RAM' region */
105462306a36Sopenharmony_ci	parent = request_resource_conflict(&iomem_resource, res);
105562306a36Sopenharmony_ci	ret = parent ? request_resource(parent, res) : 0;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	/*
105862306a36Sopenharmony_ci	 * Given that efi_mem_reserve_iomem() can be called at any
105962306a36Sopenharmony_ci	 * time, only call memblock_reserve() if the architecture
106062306a36Sopenharmony_ci	 * keeps the infrastructure around.
106162306a36Sopenharmony_ci	 */
106262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK) && !ret)
106362306a36Sopenharmony_ci		memblock_reserve(addr, size);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	return ret;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ciint __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct linux_efi_memreserve *rsv;
107162306a36Sopenharmony_ci	unsigned long prsv;
107262306a36Sopenharmony_ci	int rc, index;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (efi_memreserve_root == (void *)ULONG_MAX)
107562306a36Sopenharmony_ci		return -ENODEV;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (!efi_memreserve_root) {
107862306a36Sopenharmony_ci		rc = efi_memreserve_map_root();
107962306a36Sopenharmony_ci		if (rc)
108062306a36Sopenharmony_ci			return rc;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* first try to find a slot in an existing linked list entry */
108462306a36Sopenharmony_ci	for (prsv = efi_memreserve_root->next; prsv; ) {
108562306a36Sopenharmony_ci		rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
108662306a36Sopenharmony_ci		if (!rsv)
108762306a36Sopenharmony_ci			return -ENOMEM;
108862306a36Sopenharmony_ci		index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
108962306a36Sopenharmony_ci		if (index < rsv->size) {
109062306a36Sopenharmony_ci			rsv->entry[index].base = addr;
109162306a36Sopenharmony_ci			rsv->entry[index].size = size;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci			memunmap(rsv);
109462306a36Sopenharmony_ci			return efi_mem_reserve_iomem(addr, size);
109562306a36Sopenharmony_ci		}
109662306a36Sopenharmony_ci		prsv = rsv->next;
109762306a36Sopenharmony_ci		memunmap(rsv);
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* no slot found - allocate a new linked list entry */
110162306a36Sopenharmony_ci	rsv = (struct linux_efi_memreserve *)__get_free_page(GFP_ATOMIC);
110262306a36Sopenharmony_ci	if (!rsv)
110362306a36Sopenharmony_ci		return -ENOMEM;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	rc = efi_mem_reserve_iomem(__pa(rsv), SZ_4K);
110662306a36Sopenharmony_ci	if (rc) {
110762306a36Sopenharmony_ci		free_page((unsigned long)rsv);
110862306a36Sopenharmony_ci		return rc;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/*
111262306a36Sopenharmony_ci	 * The memremap() call above assumes that a linux_efi_memreserve entry
111362306a36Sopenharmony_ci	 * never crosses a page boundary, so let's ensure that this remains true
111462306a36Sopenharmony_ci	 * even when kexec'ing a 4k pages kernel from a >4k pages kernel, by
111562306a36Sopenharmony_ci	 * using SZ_4K explicitly in the size calculation below.
111662306a36Sopenharmony_ci	 */
111762306a36Sopenharmony_ci	rsv->size = EFI_MEMRESERVE_COUNT(SZ_4K);
111862306a36Sopenharmony_ci	atomic_set(&rsv->count, 1);
111962306a36Sopenharmony_ci	rsv->entry[0].base = addr;
112062306a36Sopenharmony_ci	rsv->entry[0].size = size;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	spin_lock(&efi_mem_reserve_persistent_lock);
112362306a36Sopenharmony_ci	rsv->next = efi_memreserve_root->next;
112462306a36Sopenharmony_ci	efi_memreserve_root->next = __pa(rsv);
112562306a36Sopenharmony_ci	spin_unlock(&efi_mem_reserve_persistent_lock);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	return efi_mem_reserve_iomem(addr, size);
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic int __init efi_memreserve_root_init(void)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	if (efi_memreserve_root)
113362306a36Sopenharmony_ci		return 0;
113462306a36Sopenharmony_ci	if (efi_memreserve_map_root())
113562306a36Sopenharmony_ci		efi_memreserve_root = (void *)ULONG_MAX;
113662306a36Sopenharmony_ci	return 0;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ciearly_initcall(efi_memreserve_root_init);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci#ifdef CONFIG_KEXEC
114162306a36Sopenharmony_cistatic int update_efi_random_seed(struct notifier_block *nb,
114262306a36Sopenharmony_ci				  unsigned long code, void *unused)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct linux_efi_random_seed *seed;
114562306a36Sopenharmony_ci	u32 size = 0;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	if (!kexec_in_progress)
114862306a36Sopenharmony_ci		return NOTIFY_DONE;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	seed = memremap(efi_rng_seed, sizeof(*seed), MEMREMAP_WB);
115162306a36Sopenharmony_ci	if (seed != NULL) {
115262306a36Sopenharmony_ci		size = min(seed->size, EFI_RANDOM_SEED_SIZE);
115362306a36Sopenharmony_ci		memunmap(seed);
115462306a36Sopenharmony_ci	} else {
115562306a36Sopenharmony_ci		pr_err("Could not map UEFI random seed!\n");
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci	if (size > 0) {
115862306a36Sopenharmony_ci		seed = memremap(efi_rng_seed, sizeof(*seed) + size,
115962306a36Sopenharmony_ci				MEMREMAP_WB);
116062306a36Sopenharmony_ci		if (seed != NULL) {
116162306a36Sopenharmony_ci			seed->size = size;
116262306a36Sopenharmony_ci			get_random_bytes(seed->bits, seed->size);
116362306a36Sopenharmony_ci			memunmap(seed);
116462306a36Sopenharmony_ci		} else {
116562306a36Sopenharmony_ci			pr_err("Could not map UEFI random seed!\n");
116662306a36Sopenharmony_ci		}
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci	return NOTIFY_DONE;
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic struct notifier_block efi_random_seed_nb = {
117262306a36Sopenharmony_ci	.notifier_call = update_efi_random_seed,
117362306a36Sopenharmony_ci};
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cistatic int __init register_update_efi_random_seed(void)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	if (efi_rng_seed == EFI_INVALID_TABLE_ADDR)
117862306a36Sopenharmony_ci		return 0;
117962306a36Sopenharmony_ci	return register_reboot_notifier(&efi_random_seed_nb);
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_cilate_initcall(register_update_efi_random_seed);
118262306a36Sopenharmony_ci#endif
1183