162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Common EFI (Extensible Firmware Interface) support functions
462306a36Sopenharmony_ci * Based on Extensible Firmware Interface Specification version 1.0
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1999 VA Linux Systems
762306a36Sopenharmony_ci * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
862306a36Sopenharmony_ci * Copyright (C) 1999-2002 Hewlett-Packard Co.
962306a36Sopenharmony_ci *	David Mosberger-Tang <davidm@hpl.hp.com>
1062306a36Sopenharmony_ci *	Stephane Eranian <eranian@hpl.hp.com>
1162306a36Sopenharmony_ci * Copyright (C) 2005-2008 Intel Co.
1262306a36Sopenharmony_ci *	Fenghua Yu <fenghua.yu@intel.com>
1362306a36Sopenharmony_ci *	Bibo Mao <bibo.mao@intel.com>
1462306a36Sopenharmony_ci *	Chandramouli Narayanan <mouli@linux.intel.com>
1562306a36Sopenharmony_ci *	Huang Ying <ying.huang@intel.com>
1662306a36Sopenharmony_ci * Copyright (C) 2013 SuSE Labs
1762306a36Sopenharmony_ci *	Borislav Petkov <bp@suse.de> - runtime services VA mapping
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Copied from efi_32.c to eliminate the duplicated code between EFI
2062306a36Sopenharmony_ci * 32/64 support code. --ying 2007-10-26
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * All EFI Runtime Services are not implemented yet as EFI only
2362306a36Sopenharmony_ci * supports physical mode addressing on SoftSDV. This is to be fixed
2462306a36Sopenharmony_ci * in a future version.  --drummond 1999-07-20
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Implemented EFI runtime services and virtual mode calls.  --davidm
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * Goutham Rao: <goutham.rao@intel.com>
2962306a36Sopenharmony_ci *	Skip non-WB memory and ignore empty memory ranges.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <linux/kernel.h>
3562306a36Sopenharmony_ci#include <linux/init.h>
3662306a36Sopenharmony_ci#include <linux/efi.h>
3762306a36Sopenharmony_ci#include <linux/efi-bgrt.h>
3862306a36Sopenharmony_ci#include <linux/export.h>
3962306a36Sopenharmony_ci#include <linux/memblock.h>
4062306a36Sopenharmony_ci#include <linux/slab.h>
4162306a36Sopenharmony_ci#include <linux/spinlock.h>
4262306a36Sopenharmony_ci#include <linux/uaccess.h>
4362306a36Sopenharmony_ci#include <linux/time.h>
4462306a36Sopenharmony_ci#include <linux/io.h>
4562306a36Sopenharmony_ci#include <linux/reboot.h>
4662306a36Sopenharmony_ci#include <linux/bcd.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#include <asm/setup.h>
4962306a36Sopenharmony_ci#include <asm/efi.h>
5062306a36Sopenharmony_ci#include <asm/e820/api.h>
5162306a36Sopenharmony_ci#include <asm/time.h>
5262306a36Sopenharmony_ci#include <asm/tlbflush.h>
5362306a36Sopenharmony_ci#include <asm/x86_init.h>
5462306a36Sopenharmony_ci#include <asm/uv/uv.h>
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic unsigned long efi_systab_phys __initdata;
5762306a36Sopenharmony_cistatic unsigned long prop_phys = EFI_INVALID_TABLE_ADDR;
5862306a36Sopenharmony_cistatic unsigned long uga_phys = EFI_INVALID_TABLE_ADDR;
5962306a36Sopenharmony_cistatic unsigned long efi_runtime, efi_nr_tables;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciunsigned long efi_fw_vendor, efi_config_table;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic const efi_config_table_type_t arch_tables[] __initconst = {
6462306a36Sopenharmony_ci	{EFI_PROPERTIES_TABLE_GUID,	&prop_phys,		"PROP"		},
6562306a36Sopenharmony_ci	{UGA_IO_PROTOCOL_GUID,		&uga_phys,		"UGA"		},
6662306a36Sopenharmony_ci#ifdef CONFIG_X86_UV
6762306a36Sopenharmony_ci	{UV_SYSTEM_TABLE_GUID,		&uv_systab_phys,	"UVsystab"	},
6862306a36Sopenharmony_ci#endif
6962306a36Sopenharmony_ci	{},
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic const unsigned long * const efi_tables[] = {
7362306a36Sopenharmony_ci	&efi.acpi,
7462306a36Sopenharmony_ci	&efi.acpi20,
7562306a36Sopenharmony_ci	&efi.smbios,
7662306a36Sopenharmony_ci	&efi.smbios3,
7762306a36Sopenharmony_ci	&uga_phys,
7862306a36Sopenharmony_ci#ifdef CONFIG_X86_UV
7962306a36Sopenharmony_ci	&uv_systab_phys,
8062306a36Sopenharmony_ci#endif
8162306a36Sopenharmony_ci	&efi_fw_vendor,
8262306a36Sopenharmony_ci	&efi_runtime,
8362306a36Sopenharmony_ci	&efi_config_table,
8462306a36Sopenharmony_ci	&efi.esrt,
8562306a36Sopenharmony_ci	&prop_phys,
8662306a36Sopenharmony_ci	&efi_mem_attr_table,
8762306a36Sopenharmony_ci#ifdef CONFIG_EFI_RCI2_TABLE
8862306a36Sopenharmony_ci	&rci2_table_phys,
8962306a36Sopenharmony_ci#endif
9062306a36Sopenharmony_ci	&efi.tpm_log,
9162306a36Sopenharmony_ci	&efi.tpm_final_log,
9262306a36Sopenharmony_ci	&efi_rng_seed,
9362306a36Sopenharmony_ci#ifdef CONFIG_LOAD_UEFI_KEYS
9462306a36Sopenharmony_ci	&efi.mokvar_table,
9562306a36Sopenharmony_ci#endif
9662306a36Sopenharmony_ci#ifdef CONFIG_EFI_COCO_SECRET
9762306a36Sopenharmony_ci	&efi.coco_secret,
9862306a36Sopenharmony_ci#endif
9962306a36Sopenharmony_ci#ifdef CONFIG_UNACCEPTED_MEMORY
10062306a36Sopenharmony_ci	&efi.unaccepted,
10162306a36Sopenharmony_ci#endif
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciu64 efi_setup;		/* efi setup_data physical address */
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int add_efi_memmap __initdata;
10762306a36Sopenharmony_cistatic int __init setup_add_efi_memmap(char *arg)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	add_efi_memmap = 1;
11062306a36Sopenharmony_ci	return 0;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ciearly_param("add_efi_memmap", setup_add_efi_memmap);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/*
11562306a36Sopenharmony_ci * Tell the kernel about the EFI memory map.  This might include
11662306a36Sopenharmony_ci * more than the max 128 entries that can fit in the passed in e820
11762306a36Sopenharmony_ci * legacy (zeropage) memory map, but the kernel's e820 table can hold
11862306a36Sopenharmony_ci * E820_MAX_ENTRIES.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void __init do_add_efi_memmap(void)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	efi_memory_desc_t *md;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (!efi_enabled(EFI_MEMMAP))
12662306a36Sopenharmony_ci		return;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
12962306a36Sopenharmony_ci		unsigned long long start = md->phys_addr;
13062306a36Sopenharmony_ci		unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
13162306a36Sopenharmony_ci		int e820_type;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		switch (md->type) {
13462306a36Sopenharmony_ci		case EFI_LOADER_CODE:
13562306a36Sopenharmony_ci		case EFI_LOADER_DATA:
13662306a36Sopenharmony_ci		case EFI_BOOT_SERVICES_CODE:
13762306a36Sopenharmony_ci		case EFI_BOOT_SERVICES_DATA:
13862306a36Sopenharmony_ci		case EFI_CONVENTIONAL_MEMORY:
13962306a36Sopenharmony_ci			if (efi_soft_reserve_enabled()
14062306a36Sopenharmony_ci			    && (md->attribute & EFI_MEMORY_SP))
14162306a36Sopenharmony_ci				e820_type = E820_TYPE_SOFT_RESERVED;
14262306a36Sopenharmony_ci			else if (md->attribute & EFI_MEMORY_WB)
14362306a36Sopenharmony_ci				e820_type = E820_TYPE_RAM;
14462306a36Sopenharmony_ci			else
14562306a36Sopenharmony_ci				e820_type = E820_TYPE_RESERVED;
14662306a36Sopenharmony_ci			break;
14762306a36Sopenharmony_ci		case EFI_ACPI_RECLAIM_MEMORY:
14862306a36Sopenharmony_ci			e820_type = E820_TYPE_ACPI;
14962306a36Sopenharmony_ci			break;
15062306a36Sopenharmony_ci		case EFI_ACPI_MEMORY_NVS:
15162306a36Sopenharmony_ci			e820_type = E820_TYPE_NVS;
15262306a36Sopenharmony_ci			break;
15362306a36Sopenharmony_ci		case EFI_UNUSABLE_MEMORY:
15462306a36Sopenharmony_ci			e820_type = E820_TYPE_UNUSABLE;
15562306a36Sopenharmony_ci			break;
15662306a36Sopenharmony_ci		case EFI_PERSISTENT_MEMORY:
15762306a36Sopenharmony_ci			e820_type = E820_TYPE_PMEM;
15862306a36Sopenharmony_ci			break;
15962306a36Sopenharmony_ci		default:
16062306a36Sopenharmony_ci			/*
16162306a36Sopenharmony_ci			 * EFI_RESERVED_TYPE EFI_RUNTIME_SERVICES_CODE
16262306a36Sopenharmony_ci			 * EFI_RUNTIME_SERVICES_DATA EFI_MEMORY_MAPPED_IO
16362306a36Sopenharmony_ci			 * EFI_MEMORY_MAPPED_IO_PORT_SPACE EFI_PAL_CODE
16462306a36Sopenharmony_ci			 */
16562306a36Sopenharmony_ci			e820_type = E820_TYPE_RESERVED;
16662306a36Sopenharmony_ci			break;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		e820__range_add(start, size, e820_type);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	e820__update_table(e820_table);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * Given add_efi_memmap defaults to 0 and there is no alternative
17662306a36Sopenharmony_ci * e820 mechanism for soft-reserved memory, import the full EFI memory
17762306a36Sopenharmony_ci * map if soft reservations are present and enabled. Otherwise, the
17862306a36Sopenharmony_ci * mechanism to disable the kernel's consideration of EFI_MEMORY_SP is
17962306a36Sopenharmony_ci * the efi=nosoftreserve option.
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cistatic bool do_efi_soft_reserve(void)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	efi_memory_desc_t *md;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!efi_enabled(EFI_MEMMAP))
18662306a36Sopenharmony_ci		return false;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (!efi_soft_reserve_enabled())
18962306a36Sopenharmony_ci		return false;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	for_each_efi_memory_desc(md)
19262306a36Sopenharmony_ci		if (md->type == EFI_CONVENTIONAL_MEMORY &&
19362306a36Sopenharmony_ci		    (md->attribute & EFI_MEMORY_SP))
19462306a36Sopenharmony_ci			return true;
19562306a36Sopenharmony_ci	return false;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ciint __init efi_memblock_x86_reserve_range(void)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct efi_info *e = &boot_params.efi_info;
20162306a36Sopenharmony_ci	struct efi_memory_map_data data;
20262306a36Sopenharmony_ci	phys_addr_t pmap;
20362306a36Sopenharmony_ci	int rv;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	if (efi_enabled(EFI_PARAVIRT))
20662306a36Sopenharmony_ci		return 0;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Can't handle firmware tables above 4GB on i386 */
20962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_X86_32) && e->efi_memmap_hi > 0) {
21062306a36Sopenharmony_ci		pr_err("Memory map is above 4GB, disabling EFI.\n");
21162306a36Sopenharmony_ci		return -EINVAL;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci	pmap = (phys_addr_t)(e->efi_memmap | ((u64)e->efi_memmap_hi << 32));
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	data.phys_map		= pmap;
21662306a36Sopenharmony_ci	data.size 		= e->efi_memmap_size;
21762306a36Sopenharmony_ci	data.desc_size		= e->efi_memdesc_size;
21862306a36Sopenharmony_ci	data.desc_version	= e->efi_memdesc_version;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (!efi_enabled(EFI_PARAVIRT)) {
22162306a36Sopenharmony_ci		rv = efi_memmap_init_early(&data);
22262306a36Sopenharmony_ci		if (rv)
22362306a36Sopenharmony_ci			return rv;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (add_efi_memmap || do_efi_soft_reserve())
22762306a36Sopenharmony_ci		do_add_efi_memmap();
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	efi_fake_memmap_early();
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	WARN(efi.memmap.desc_version != 1,
23262306a36Sopenharmony_ci	     "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
23362306a36Sopenharmony_ci	     efi.memmap.desc_version);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size);
23662306a36Sopenharmony_ci	set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#define OVERFLOW_ADDR_SHIFT	(64 - EFI_PAGE_SHIFT)
24262306a36Sopenharmony_ci#define OVERFLOW_ADDR_MASK	(U64_MAX << OVERFLOW_ADDR_SHIFT)
24362306a36Sopenharmony_ci#define U64_HIGH_BIT		(~(U64_MAX >> 1))
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic bool __init efi_memmap_entry_valid(const efi_memory_desc_t *md, int i)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	u64 end = (md->num_pages << EFI_PAGE_SHIFT) + md->phys_addr - 1;
24862306a36Sopenharmony_ci	u64 end_hi = 0;
24962306a36Sopenharmony_ci	char buf[64];
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (md->num_pages == 0) {
25262306a36Sopenharmony_ci		end = 0;
25362306a36Sopenharmony_ci	} else if (md->num_pages > EFI_PAGES_MAX ||
25462306a36Sopenharmony_ci		   EFI_PAGES_MAX - md->num_pages <
25562306a36Sopenharmony_ci		   (md->phys_addr >> EFI_PAGE_SHIFT)) {
25662306a36Sopenharmony_ci		end_hi = (md->num_pages & OVERFLOW_ADDR_MASK)
25762306a36Sopenharmony_ci			>> OVERFLOW_ADDR_SHIFT;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		if ((md->phys_addr & U64_HIGH_BIT) && !(end & U64_HIGH_BIT))
26062306a36Sopenharmony_ci			end_hi += 1;
26162306a36Sopenharmony_ci	} else {
26262306a36Sopenharmony_ci		return true;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	pr_warn_once(FW_BUG "Invalid EFI memory map entries:\n");
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (end_hi) {
26862306a36Sopenharmony_ci		pr_warn("mem%02u: %s range=[0x%016llx-0x%llx%016llx] (invalid)\n",
26962306a36Sopenharmony_ci			i, efi_md_typeattr_format(buf, sizeof(buf), md),
27062306a36Sopenharmony_ci			md->phys_addr, end_hi, end);
27162306a36Sopenharmony_ci	} else {
27262306a36Sopenharmony_ci		pr_warn("mem%02u: %s range=[0x%016llx-0x%016llx] (invalid)\n",
27362306a36Sopenharmony_ci			i, efi_md_typeattr_format(buf, sizeof(buf), md),
27462306a36Sopenharmony_ci			md->phys_addr, end);
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci	return false;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void __init efi_clean_memmap(void)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	efi_memory_desc_t *out = efi.memmap.map;
28262306a36Sopenharmony_ci	const efi_memory_desc_t *in = out;
28362306a36Sopenharmony_ci	const efi_memory_desc_t *end = efi.memmap.map_end;
28462306a36Sopenharmony_ci	int i, n_removal;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	for (i = n_removal = 0; in < end; i++) {
28762306a36Sopenharmony_ci		if (efi_memmap_entry_valid(in, i)) {
28862306a36Sopenharmony_ci			if (out != in)
28962306a36Sopenharmony_ci				memcpy(out, in, efi.memmap.desc_size);
29062306a36Sopenharmony_ci			out = (void *)out + efi.memmap.desc_size;
29162306a36Sopenharmony_ci		} else {
29262306a36Sopenharmony_ci			n_removal++;
29362306a36Sopenharmony_ci		}
29462306a36Sopenharmony_ci		in = (void *)in + efi.memmap.desc_size;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (n_removal > 0) {
29862306a36Sopenharmony_ci		struct efi_memory_map_data data = {
29962306a36Sopenharmony_ci			.phys_map	= efi.memmap.phys_map,
30062306a36Sopenharmony_ci			.desc_version	= efi.memmap.desc_version,
30162306a36Sopenharmony_ci			.desc_size	= efi.memmap.desc_size,
30262306a36Sopenharmony_ci			.size		= efi.memmap.desc_size * (efi.memmap.nr_map - n_removal),
30362306a36Sopenharmony_ci			.flags		= 0,
30462306a36Sopenharmony_ci		};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		pr_warn("Removing %d invalid memory map entries.\n", n_removal);
30762306a36Sopenharmony_ci		efi_memmap_install(&data);
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/*
31262306a36Sopenharmony_ci * Firmware can use EfiMemoryMappedIO to request that MMIO regions be
31362306a36Sopenharmony_ci * mapped by the OS so they can be accessed by EFI runtime services, but
31462306a36Sopenharmony_ci * should have no other significance to the OS (UEFI r2.10, sec 7.2).
31562306a36Sopenharmony_ci * However, most bootloaders and EFI stubs convert EfiMemoryMappedIO
31662306a36Sopenharmony_ci * regions to E820_TYPE_RESERVED entries, which prevent Linux from
31762306a36Sopenharmony_ci * allocating space from them (see remove_e820_regions()).
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * Some platforms use EfiMemoryMappedIO entries for PCI MMCONFIG space and
32062306a36Sopenharmony_ci * PCI host bridge windows, which means Linux can't allocate BAR space for
32162306a36Sopenharmony_ci * hot-added devices.
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * Remove large EfiMemoryMappedIO regions from the E820 map to avoid this
32462306a36Sopenharmony_ci * problem.
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * Retain small EfiMemoryMappedIO regions because on some platforms, these
32762306a36Sopenharmony_ci * describe non-window space that's included in host bridge _CRS.  If we
32862306a36Sopenharmony_ci * assign that space to PCI devices, they don't work.
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_cistatic void __init efi_remove_e820_mmio(void)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	efi_memory_desc_t *md;
33362306a36Sopenharmony_ci	u64 size, start, end;
33462306a36Sopenharmony_ci	int i = 0;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
33762306a36Sopenharmony_ci		if (md->type == EFI_MEMORY_MAPPED_IO) {
33862306a36Sopenharmony_ci			size = md->num_pages << EFI_PAGE_SHIFT;
33962306a36Sopenharmony_ci			start = md->phys_addr;
34062306a36Sopenharmony_ci			end = start + size - 1;
34162306a36Sopenharmony_ci			if (size >= 256*1024) {
34262306a36Sopenharmony_ci				pr_info("Remove mem%02u: MMIO range=[0x%08llx-0x%08llx] (%lluMB) from e820 map\n",
34362306a36Sopenharmony_ci					i, start, end, size >> 20);
34462306a36Sopenharmony_ci				e820__range_remove(start, size,
34562306a36Sopenharmony_ci						   E820_TYPE_RESERVED, 1);
34662306a36Sopenharmony_ci			} else {
34762306a36Sopenharmony_ci				pr_info("Not removing mem%02u: MMIO range=[0x%08llx-0x%08llx] (%lluKB) from e820 map\n",
34862306a36Sopenharmony_ci					i, start, end, size >> 10);
34962306a36Sopenharmony_ci			}
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci		i++;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_civoid __init efi_print_memmap(void)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	efi_memory_desc_t *md;
35862306a36Sopenharmony_ci	int i = 0;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
36162306a36Sopenharmony_ci		char buf[64];
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		pr_info("mem%02u: %s range=[0x%016llx-0x%016llx] (%lluMB)\n",
36462306a36Sopenharmony_ci			i++, efi_md_typeattr_format(buf, sizeof(buf), md),
36562306a36Sopenharmony_ci			md->phys_addr,
36662306a36Sopenharmony_ci			md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1,
36762306a36Sopenharmony_ci			(md->num_pages >> (20 - EFI_PAGE_SHIFT)));
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic int __init efi_systab_init(unsigned long phys)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
37462306a36Sopenharmony_ci					  : sizeof(efi_system_table_32_t);
37562306a36Sopenharmony_ci	const efi_table_hdr_t *hdr;
37662306a36Sopenharmony_ci	bool over4g = false;
37762306a36Sopenharmony_ci	void *p;
37862306a36Sopenharmony_ci	int ret;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	hdr = p = early_memremap_ro(phys, size);
38162306a36Sopenharmony_ci	if (p == NULL) {
38262306a36Sopenharmony_ci		pr_err("Couldn't map the system table!\n");
38362306a36Sopenharmony_ci		return -ENOMEM;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	ret = efi_systab_check_header(hdr);
38762306a36Sopenharmony_ci	if (ret) {
38862306a36Sopenharmony_ci		early_memunmap(p, size);
38962306a36Sopenharmony_ci		return ret;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (efi_enabled(EFI_64BIT)) {
39362306a36Sopenharmony_ci		const efi_system_table_64_t *systab64 = p;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci		efi_runtime	= systab64->runtime;
39662306a36Sopenharmony_ci		over4g		= systab64->runtime > U32_MAX;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		if (efi_setup) {
39962306a36Sopenharmony_ci			struct efi_setup_data *data;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci			data = early_memremap_ro(efi_setup, sizeof(*data));
40262306a36Sopenharmony_ci			if (!data) {
40362306a36Sopenharmony_ci				early_memunmap(p, size);
40462306a36Sopenharmony_ci				return -ENOMEM;
40562306a36Sopenharmony_ci			}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci			efi_fw_vendor		= (unsigned long)data->fw_vendor;
40862306a36Sopenharmony_ci			efi_config_table	= (unsigned long)data->tables;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci			over4g |= data->fw_vendor	> U32_MAX ||
41162306a36Sopenharmony_ci				  data->tables		> U32_MAX;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci			early_memunmap(data, sizeof(*data));
41462306a36Sopenharmony_ci		} else {
41562306a36Sopenharmony_ci			efi_fw_vendor		= systab64->fw_vendor;
41662306a36Sopenharmony_ci			efi_config_table	= systab64->tables;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci			over4g |= systab64->fw_vendor	> U32_MAX ||
41962306a36Sopenharmony_ci				  systab64->tables	> U32_MAX;
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci		efi_nr_tables = systab64->nr_tables;
42262306a36Sopenharmony_ci	} else {
42362306a36Sopenharmony_ci		const efi_system_table_32_t *systab32 = p;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		efi_fw_vendor		= systab32->fw_vendor;
42662306a36Sopenharmony_ci		efi_runtime		= systab32->runtime;
42762306a36Sopenharmony_ci		efi_config_table	= systab32->tables;
42862306a36Sopenharmony_ci		efi_nr_tables		= systab32->nr_tables;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	efi.runtime_version = hdr->revision;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	efi_systab_report_header(hdr, efi_fw_vendor);
43462306a36Sopenharmony_ci	early_memunmap(p, size);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_X86_32) && over4g) {
43762306a36Sopenharmony_ci		pr_err("EFI data located above 4GB, disabling EFI.\n");
43862306a36Sopenharmony_ci		return -EINVAL;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return 0;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int __init efi_config_init(const efi_config_table_type_t *arch_tables)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	void *config_tables;
44762306a36Sopenharmony_ci	int sz, ret;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (efi_nr_tables == 0)
45062306a36Sopenharmony_ci		return 0;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (efi_enabled(EFI_64BIT))
45362306a36Sopenharmony_ci		sz = sizeof(efi_config_table_64_t);
45462306a36Sopenharmony_ci	else
45562306a36Sopenharmony_ci		sz = sizeof(efi_config_table_32_t);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/*
45862306a36Sopenharmony_ci	 * Let's see what config tables the firmware passed to us.
45962306a36Sopenharmony_ci	 */
46062306a36Sopenharmony_ci	config_tables = early_memremap(efi_config_table, efi_nr_tables * sz);
46162306a36Sopenharmony_ci	if (config_tables == NULL) {
46262306a36Sopenharmony_ci		pr_err("Could not map Configuration table!\n");
46362306a36Sopenharmony_ci		return -ENOMEM;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	ret = efi_config_parse_tables(config_tables, efi_nr_tables,
46762306a36Sopenharmony_ci				      arch_tables);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	early_memunmap(config_tables, efi_nr_tables * sz);
47062306a36Sopenharmony_ci	return ret;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_civoid __init efi_init(void)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_X86_32) &&
47662306a36Sopenharmony_ci	    (boot_params.efi_info.efi_systab_hi ||
47762306a36Sopenharmony_ci	     boot_params.efi_info.efi_memmap_hi)) {
47862306a36Sopenharmony_ci		pr_info("Table located above 4GB, disabling EFI.\n");
47962306a36Sopenharmony_ci		return;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	efi_systab_phys = boot_params.efi_info.efi_systab |
48362306a36Sopenharmony_ci			  ((__u64)boot_params.efi_info.efi_systab_hi << 32);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (efi_systab_init(efi_systab_phys))
48662306a36Sopenharmony_ci		return;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (efi_reuse_config(efi_config_table, efi_nr_tables))
48962306a36Sopenharmony_ci		return;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (efi_config_init(arch_tables))
49262306a36Sopenharmony_ci		return;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	/*
49562306a36Sopenharmony_ci	 * Note: We currently don't support runtime services on an EFI
49662306a36Sopenharmony_ci	 * that doesn't match the kernel 32/64-bit mode.
49762306a36Sopenharmony_ci	 */
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (!efi_runtime_supported())
50062306a36Sopenharmony_ci		pr_err("No EFI runtime due to 32/64-bit mismatch with kernel\n");
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (!efi_runtime_supported() || efi_runtime_disabled()) {
50362306a36Sopenharmony_ci		efi_memmap_unmap();
50462306a36Sopenharmony_ci		return;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/* Parse the EFI Properties table if it exists */
50862306a36Sopenharmony_ci	if (prop_phys != EFI_INVALID_TABLE_ADDR) {
50962306a36Sopenharmony_ci		efi_properties_table_t *tbl;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		tbl = early_memremap_ro(prop_phys, sizeof(*tbl));
51262306a36Sopenharmony_ci		if (tbl == NULL) {
51362306a36Sopenharmony_ci			pr_err("Could not map Properties table!\n");
51462306a36Sopenharmony_ci		} else {
51562306a36Sopenharmony_ci			if (tbl->memory_protection_attribute &
51662306a36Sopenharmony_ci			    EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
51762306a36Sopenharmony_ci				set_bit(EFI_NX_PE_DATA, &efi.flags);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci			early_memunmap(tbl, sizeof(*tbl));
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
52462306a36Sopenharmony_ci	efi_clean_memmap();
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	efi_remove_e820_mmio();
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (efi_enabled(EFI_DBG))
52962306a36Sopenharmony_ci		efi_print_memmap();
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci/* Merge contiguous regions of the same type and attribute */
53362306a36Sopenharmony_cistatic void __init efi_merge_regions(void)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	efi_memory_desc_t *md, *prev_md = NULL;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
53862306a36Sopenharmony_ci		u64 prev_size;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		if (!prev_md) {
54162306a36Sopenharmony_ci			prev_md = md;
54262306a36Sopenharmony_ci			continue;
54362306a36Sopenharmony_ci		}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		if (prev_md->type != md->type ||
54662306a36Sopenharmony_ci		    prev_md->attribute != md->attribute) {
54762306a36Sopenharmony_ci			prev_md = md;
54862306a36Sopenharmony_ci			continue;
54962306a36Sopenharmony_ci		}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		prev_size = prev_md->num_pages << EFI_PAGE_SHIFT;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		if (md->phys_addr == (prev_md->phys_addr + prev_size)) {
55462306a36Sopenharmony_ci			prev_md->num_pages += md->num_pages;
55562306a36Sopenharmony_ci			md->type = EFI_RESERVED_TYPE;
55662306a36Sopenharmony_ci			md->attribute = 0;
55762306a36Sopenharmony_ci			continue;
55862306a36Sopenharmony_ci		}
55962306a36Sopenharmony_ci		prev_md = md;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic void *realloc_pages(void *old_memmap, int old_shift)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	void *ret;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	ret = (void *)__get_free_pages(GFP_KERNEL, old_shift + 1);
56862306a36Sopenharmony_ci	if (!ret)
56962306a36Sopenharmony_ci		goto out;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/*
57262306a36Sopenharmony_ci	 * A first-time allocation doesn't have anything to copy.
57362306a36Sopenharmony_ci	 */
57462306a36Sopenharmony_ci	if (!old_memmap)
57562306a36Sopenharmony_ci		return ret;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	memcpy(ret, old_memmap, PAGE_SIZE << old_shift);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ciout:
58062306a36Sopenharmony_ci	free_pages((unsigned long)old_memmap, old_shift);
58162306a36Sopenharmony_ci	return ret;
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci/*
58562306a36Sopenharmony_ci * Iterate the EFI memory map in reverse order because the regions
58662306a36Sopenharmony_ci * will be mapped top-down. The end result is the same as if we had
58762306a36Sopenharmony_ci * mapped things forward, but doesn't require us to change the
58862306a36Sopenharmony_ci * existing implementation of efi_map_region().
58962306a36Sopenharmony_ci */
59062306a36Sopenharmony_cistatic inline void *efi_map_next_entry_reverse(void *entry)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	/* Initial call */
59362306a36Sopenharmony_ci	if (!entry)
59462306a36Sopenharmony_ci		return efi.memmap.map_end - efi.memmap.desc_size;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	entry -= efi.memmap.desc_size;
59762306a36Sopenharmony_ci	if (entry < efi.memmap.map)
59862306a36Sopenharmony_ci		return NULL;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	return entry;
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/*
60462306a36Sopenharmony_ci * efi_map_next_entry - Return the next EFI memory map descriptor
60562306a36Sopenharmony_ci * @entry: Previous EFI memory map descriptor
60662306a36Sopenharmony_ci *
60762306a36Sopenharmony_ci * This is a helper function to iterate over the EFI memory map, which
60862306a36Sopenharmony_ci * we do in different orders depending on the current configuration.
60962306a36Sopenharmony_ci *
61062306a36Sopenharmony_ci * To begin traversing the memory map @entry must be %NULL.
61162306a36Sopenharmony_ci *
61262306a36Sopenharmony_ci * Returns %NULL when we reach the end of the memory map.
61362306a36Sopenharmony_ci */
61462306a36Sopenharmony_cistatic void *efi_map_next_entry(void *entry)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	if (efi_enabled(EFI_64BIT)) {
61762306a36Sopenharmony_ci		/*
61862306a36Sopenharmony_ci		 * Starting in UEFI v2.5 the EFI_PROPERTIES_TABLE
61962306a36Sopenharmony_ci		 * config table feature requires us to map all entries
62062306a36Sopenharmony_ci		 * in the same order as they appear in the EFI memory
62162306a36Sopenharmony_ci		 * map. That is to say, entry N must have a lower
62262306a36Sopenharmony_ci		 * virtual address than entry N+1. This is because the
62362306a36Sopenharmony_ci		 * firmware toolchain leaves relative references in
62462306a36Sopenharmony_ci		 * the code/data sections, which are split and become
62562306a36Sopenharmony_ci		 * separate EFI memory regions. Mapping things
62662306a36Sopenharmony_ci		 * out-of-order leads to the firmware accessing
62762306a36Sopenharmony_ci		 * unmapped addresses.
62862306a36Sopenharmony_ci		 *
62962306a36Sopenharmony_ci		 * Since we need to map things this way whether or not
63062306a36Sopenharmony_ci		 * the kernel actually makes use of
63162306a36Sopenharmony_ci		 * EFI_PROPERTIES_TABLE, let's just switch to this
63262306a36Sopenharmony_ci		 * scheme by default for 64-bit.
63362306a36Sopenharmony_ci		 */
63462306a36Sopenharmony_ci		return efi_map_next_entry_reverse(entry);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	/* Initial call */
63862306a36Sopenharmony_ci	if (!entry)
63962306a36Sopenharmony_ci		return efi.memmap.map;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	entry += efi.memmap.desc_size;
64262306a36Sopenharmony_ci	if (entry >= efi.memmap.map_end)
64362306a36Sopenharmony_ci		return NULL;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	return entry;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic bool should_map_region(efi_memory_desc_t *md)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	/*
65162306a36Sopenharmony_ci	 * Runtime regions always require runtime mappings (obviously).
65262306a36Sopenharmony_ci	 */
65362306a36Sopenharmony_ci	if (md->attribute & EFI_MEMORY_RUNTIME)
65462306a36Sopenharmony_ci		return true;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/*
65762306a36Sopenharmony_ci	 * 32-bit EFI doesn't suffer from the bug that requires us to
65862306a36Sopenharmony_ci	 * reserve boot services regions, and mixed mode support
65962306a36Sopenharmony_ci	 * doesn't exist for 32-bit kernels.
66062306a36Sopenharmony_ci	 */
66162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_X86_32))
66262306a36Sopenharmony_ci		return false;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/*
66562306a36Sopenharmony_ci	 * EFI specific purpose memory may be reserved by default
66662306a36Sopenharmony_ci	 * depending on kernel config and boot options.
66762306a36Sopenharmony_ci	 */
66862306a36Sopenharmony_ci	if (md->type == EFI_CONVENTIONAL_MEMORY &&
66962306a36Sopenharmony_ci	    efi_soft_reserve_enabled() &&
67062306a36Sopenharmony_ci	    (md->attribute & EFI_MEMORY_SP))
67162306a36Sopenharmony_ci		return false;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/*
67462306a36Sopenharmony_ci	 * Map all of RAM so that we can access arguments in the 1:1
67562306a36Sopenharmony_ci	 * mapping when making EFI runtime calls.
67662306a36Sopenharmony_ci	 */
67762306a36Sopenharmony_ci	if (efi_is_mixed()) {
67862306a36Sopenharmony_ci		if (md->type == EFI_CONVENTIONAL_MEMORY ||
67962306a36Sopenharmony_ci		    md->type == EFI_LOADER_DATA ||
68062306a36Sopenharmony_ci		    md->type == EFI_LOADER_CODE)
68162306a36Sopenharmony_ci			return true;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/*
68562306a36Sopenharmony_ci	 * Map boot services regions as a workaround for buggy
68662306a36Sopenharmony_ci	 * firmware that accesses them even when they shouldn't.
68762306a36Sopenharmony_ci	 *
68862306a36Sopenharmony_ci	 * See efi_{reserve,free}_boot_services().
68962306a36Sopenharmony_ci	 */
69062306a36Sopenharmony_ci	if (md->type == EFI_BOOT_SERVICES_CODE ||
69162306a36Sopenharmony_ci	    md->type == EFI_BOOT_SERVICES_DATA)
69262306a36Sopenharmony_ci		return true;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return false;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci/*
69862306a36Sopenharmony_ci * Map the efi memory ranges of the runtime services and update new_mmap with
69962306a36Sopenharmony_ci * virtual addresses.
70062306a36Sopenharmony_ci */
70162306a36Sopenharmony_cistatic void * __init efi_map_regions(int *count, int *pg_shift)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	void *p, *new_memmap = NULL;
70462306a36Sopenharmony_ci	unsigned long left = 0;
70562306a36Sopenharmony_ci	unsigned long desc_size;
70662306a36Sopenharmony_ci	efi_memory_desc_t *md;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	desc_size = efi.memmap.desc_size;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	p = NULL;
71162306a36Sopenharmony_ci	while ((p = efi_map_next_entry(p))) {
71262306a36Sopenharmony_ci		md = p;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		if (!should_map_region(md))
71562306a36Sopenharmony_ci			continue;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		efi_map_region(md);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci		if (left < desc_size) {
72062306a36Sopenharmony_ci			new_memmap = realloc_pages(new_memmap, *pg_shift);
72162306a36Sopenharmony_ci			if (!new_memmap)
72262306a36Sopenharmony_ci				return NULL;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci			left += PAGE_SIZE << *pg_shift;
72562306a36Sopenharmony_ci			(*pg_shift)++;
72662306a36Sopenharmony_ci		}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		memcpy(new_memmap + (*count * desc_size), md, desc_size);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		left -= desc_size;
73162306a36Sopenharmony_ci		(*count)++;
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	return new_memmap;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic void __init kexec_enter_virtual_mode(void)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci#ifdef CONFIG_KEXEC_CORE
74062306a36Sopenharmony_ci	efi_memory_desc_t *md;
74162306a36Sopenharmony_ci	unsigned int num_pages;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/*
74462306a36Sopenharmony_ci	 * We don't do virtual mode, since we don't do runtime services, on
74562306a36Sopenharmony_ci	 * non-native EFI.
74662306a36Sopenharmony_ci	 */
74762306a36Sopenharmony_ci	if (efi_is_mixed()) {
74862306a36Sopenharmony_ci		efi_memmap_unmap();
74962306a36Sopenharmony_ci		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
75062306a36Sopenharmony_ci		return;
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (efi_alloc_page_tables()) {
75462306a36Sopenharmony_ci		pr_err("Failed to allocate EFI page tables\n");
75562306a36Sopenharmony_ci		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
75662306a36Sopenharmony_ci		return;
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	/*
76062306a36Sopenharmony_ci	* Map efi regions which were passed via setup_data. The virt_addr is a
76162306a36Sopenharmony_ci	* fixed addr which was used in first kernel of a kexec boot.
76262306a36Sopenharmony_ci	*/
76362306a36Sopenharmony_ci	for_each_efi_memory_desc(md)
76462306a36Sopenharmony_ci		efi_map_region_fixed(md); /* FIXME: add error handling */
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	/*
76762306a36Sopenharmony_ci	 * Unregister the early EFI memmap from efi_init() and install
76862306a36Sopenharmony_ci	 * the new EFI memory map.
76962306a36Sopenharmony_ci	 */
77062306a36Sopenharmony_ci	efi_memmap_unmap();
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (efi_memmap_init_late(efi.memmap.phys_map,
77362306a36Sopenharmony_ci				 efi.memmap.desc_size * efi.memmap.nr_map)) {
77462306a36Sopenharmony_ci		pr_err("Failed to remap late EFI memory map\n");
77562306a36Sopenharmony_ci		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
77662306a36Sopenharmony_ci		return;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE);
78062306a36Sopenharmony_ci	num_pages >>= PAGE_SHIFT;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (efi_setup_page_tables(efi.memmap.phys_map, num_pages)) {
78362306a36Sopenharmony_ci		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
78462306a36Sopenharmony_ci		return;
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	efi_sync_low_kernel_mappings();
78862306a36Sopenharmony_ci	efi_native_runtime_setup();
78962306a36Sopenharmony_ci#endif
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci/*
79362306a36Sopenharmony_ci * This function will switch the EFI runtime services to virtual mode.
79462306a36Sopenharmony_ci * Essentially, we look through the EFI memmap and map every region that
79562306a36Sopenharmony_ci * has the runtime attribute bit set in its memory descriptor into the
79662306a36Sopenharmony_ci * efi_pgd page table.
79762306a36Sopenharmony_ci *
79862306a36Sopenharmony_ci * The new method does a pagetable switch in a preemption-safe manner
79962306a36Sopenharmony_ci * so that we're in a different address space when calling a runtime
80062306a36Sopenharmony_ci * function. For function arguments passing we do copy the PUDs of the
80162306a36Sopenharmony_ci * kernel page table into efi_pgd prior to each call.
80262306a36Sopenharmony_ci *
80362306a36Sopenharmony_ci * Specially for kexec boot, efi runtime maps in previous kernel should
80462306a36Sopenharmony_ci * be passed in via setup_data. In that case runtime ranges will be mapped
80562306a36Sopenharmony_ci * to the same virtual addresses as the first kernel, see
80662306a36Sopenharmony_ci * kexec_enter_virtual_mode().
80762306a36Sopenharmony_ci */
80862306a36Sopenharmony_cistatic void __init __efi_enter_virtual_mode(void)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	int count = 0, pg_shift = 0;
81162306a36Sopenharmony_ci	void *new_memmap = NULL;
81262306a36Sopenharmony_ci	efi_status_t status;
81362306a36Sopenharmony_ci	unsigned long pa;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (efi_alloc_page_tables()) {
81662306a36Sopenharmony_ci		pr_err("Failed to allocate EFI page tables\n");
81762306a36Sopenharmony_ci		goto err;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	efi_merge_regions();
82162306a36Sopenharmony_ci	new_memmap = efi_map_regions(&count, &pg_shift);
82262306a36Sopenharmony_ci	if (!new_memmap) {
82362306a36Sopenharmony_ci		pr_err("Error reallocating memory, EFI runtime non-functional!\n");
82462306a36Sopenharmony_ci		goto err;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	pa = __pa(new_memmap);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/*
83062306a36Sopenharmony_ci	 * Unregister the early EFI memmap from efi_init() and install
83162306a36Sopenharmony_ci	 * the new EFI memory map that we are about to pass to the
83262306a36Sopenharmony_ci	 * firmware via SetVirtualAddressMap().
83362306a36Sopenharmony_ci	 */
83462306a36Sopenharmony_ci	efi_memmap_unmap();
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (efi_memmap_init_late(pa, efi.memmap.desc_size * count)) {
83762306a36Sopenharmony_ci		pr_err("Failed to remap late EFI memory map\n");
83862306a36Sopenharmony_ci		goto err;
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	if (efi_enabled(EFI_DBG)) {
84262306a36Sopenharmony_ci		pr_info("EFI runtime memory map:\n");
84362306a36Sopenharmony_ci		efi_print_memmap();
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (efi_setup_page_tables(pa, 1 << pg_shift))
84762306a36Sopenharmony_ci		goto err;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	efi_sync_low_kernel_mappings();
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	status = efi_set_virtual_address_map(efi.memmap.desc_size * count,
85262306a36Sopenharmony_ci					     efi.memmap.desc_size,
85362306a36Sopenharmony_ci					     efi.memmap.desc_version,
85462306a36Sopenharmony_ci					     (efi_memory_desc_t *)pa,
85562306a36Sopenharmony_ci					     efi_systab_phys);
85662306a36Sopenharmony_ci	if (status != EFI_SUCCESS) {
85762306a36Sopenharmony_ci		pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",
85862306a36Sopenharmony_ci		       status);
85962306a36Sopenharmony_ci		goto err;
86062306a36Sopenharmony_ci	}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	efi_check_for_embedded_firmwares();
86362306a36Sopenharmony_ci	efi_free_boot_services();
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if (!efi_is_mixed())
86662306a36Sopenharmony_ci		efi_native_runtime_setup();
86762306a36Sopenharmony_ci	else
86862306a36Sopenharmony_ci		efi_thunk_runtime_setup();
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/*
87162306a36Sopenharmony_ci	 * Apply more restrictive page table mapping attributes now that
87262306a36Sopenharmony_ci	 * SVAM() has been called and the firmware has performed all
87362306a36Sopenharmony_ci	 * necessary relocation fixups for the new virtual addresses.
87462306a36Sopenharmony_ci	 */
87562306a36Sopenharmony_ci	efi_runtime_update_mappings();
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* clean DUMMY object */
87862306a36Sopenharmony_ci	efi_delete_dummy_variable();
87962306a36Sopenharmony_ci	return;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cierr:
88262306a36Sopenharmony_ci	clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_civoid __init efi_enter_virtual_mode(void)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	if (efi_enabled(EFI_PARAVIRT))
88862306a36Sopenharmony_ci		return;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	efi.runtime = (efi_runtime_services_t *)efi_runtime;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (efi_setup)
89362306a36Sopenharmony_ci		kexec_enter_virtual_mode();
89462306a36Sopenharmony_ci	else
89562306a36Sopenharmony_ci		__efi_enter_virtual_mode();
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	efi_dump_pagetable();
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cibool efi_is_table_address(unsigned long phys_addr)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	unsigned int i;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (phys_addr == EFI_INVALID_TABLE_ADDR)
90562306a36Sopenharmony_ci		return false;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(efi_tables); i++)
90862306a36Sopenharmony_ci		if (*(efi_tables[i]) == phys_addr)
90962306a36Sopenharmony_ci			return true;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	return false;
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cichar *efi_systab_show_arch(char *str)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	if (uga_phys != EFI_INVALID_TABLE_ADDR)
91762306a36Sopenharmony_ci		str += sprintf(str, "UGA=0x%lx\n", uga_phys);
91862306a36Sopenharmony_ci	return str;
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci#define EFI_FIELD(var) efi_ ## var
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci#define EFI_ATTR_SHOW(name) \
92462306a36Sopenharmony_cistatic ssize_t name##_show(struct kobject *kobj, \
92562306a36Sopenharmony_ci				struct kobj_attribute *attr, char *buf) \
92662306a36Sopenharmony_ci{ \
92762306a36Sopenharmony_ci	return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ciEFI_ATTR_SHOW(fw_vendor);
93162306a36Sopenharmony_ciEFI_ATTR_SHOW(runtime);
93262306a36Sopenharmony_ciEFI_ATTR_SHOW(config_table);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistruct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
93562306a36Sopenharmony_cistruct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
93662306a36Sopenharmony_cistruct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ciumode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	if (attr == &efi_attr_fw_vendor.attr) {
94162306a36Sopenharmony_ci		if (efi_enabled(EFI_PARAVIRT) ||
94262306a36Sopenharmony_ci				efi_fw_vendor == EFI_INVALID_TABLE_ADDR)
94362306a36Sopenharmony_ci			return 0;
94462306a36Sopenharmony_ci	} else if (attr == &efi_attr_runtime.attr) {
94562306a36Sopenharmony_ci		if (efi_runtime == EFI_INVALID_TABLE_ADDR)
94662306a36Sopenharmony_ci			return 0;
94762306a36Sopenharmony_ci	} else if (attr == &efi_attr_config_table.attr) {
94862306a36Sopenharmony_ci		if (efi_config_table == EFI_INVALID_TABLE_ADDR)
94962306a36Sopenharmony_ci			return 0;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci	return attr->mode;
95262306a36Sopenharmony_ci}
953