162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Extensible Firmware Interface
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Based on Extensible Firmware Interface Specification version 2.4
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2013 - 2015 Linaro Ltd.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define pr_fmt(fmt)	"efi: " fmt
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/efi.h>
1362306a36Sopenharmony_ci#include <linux/fwnode.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/memblock.h>
1662306a36Sopenharmony_ci#include <linux/mm_types.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/of_address.h>
1962306a36Sopenharmony_ci#include <linux/of_fdt.h>
2062306a36Sopenharmony_ci#include <linux/platform_device.h>
2162306a36Sopenharmony_ci#include <linux/screen_info.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <asm/efi.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciunsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int __init is_memory(efi_memory_desc_t *md)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC))
3062306a36Sopenharmony_ci		return 1;
3162306a36Sopenharmony_ci	return 0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * Translate a EFI virtual address into a physical address: this is necessary,
3662306a36Sopenharmony_ci * as some data members of the EFI system table are virtually remapped after
3762306a36Sopenharmony_ci * SetVirtualAddressMap() has been called.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic phys_addr_t __init efi_to_phys(unsigned long addr)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	efi_memory_desc_t *md;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
4462306a36Sopenharmony_ci		if (!(md->attribute & EFI_MEMORY_RUNTIME))
4562306a36Sopenharmony_ci			continue;
4662306a36Sopenharmony_ci		if (md->virt_addr == 0)
4762306a36Sopenharmony_ci			/* no virtual mapping has been installed by the stub */
4862306a36Sopenharmony_ci			break;
4962306a36Sopenharmony_ci		if (md->virt_addr <= addr &&
5062306a36Sopenharmony_ci		    (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
5162306a36Sopenharmony_ci			return md->phys_addr + addr - md->virt_addr;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci	return addr;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciextern __weak const efi_config_table_type_t efi_arch_tables[];
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void __init init_screen_info(void)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct screen_info *si;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
6362306a36Sopenharmony_ci		si = early_memremap(screen_info_table, sizeof(*si));
6462306a36Sopenharmony_ci		if (!si) {
6562306a36Sopenharmony_ci			pr_err("Could not map screen_info config table\n");
6662306a36Sopenharmony_ci			return;
6762306a36Sopenharmony_ci		}
6862306a36Sopenharmony_ci		screen_info = *si;
6962306a36Sopenharmony_ci		memset(si, 0, sizeof(*si));
7062306a36Sopenharmony_ci		early_memunmap(si, sizeof(*si));
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		if (memblock_is_map_memory(screen_info.lfb_base))
7362306a36Sopenharmony_ci			memblock_mark_nomap(screen_info.lfb_base,
7462306a36Sopenharmony_ci					    screen_info.lfb_size);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		if (IS_ENABLED(CONFIG_EFI_EARLYCON))
7762306a36Sopenharmony_ci			efi_earlycon_reprobe();
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic int __init uefi_init(u64 efi_system_table)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	efi_config_table_t *config_tables;
8462306a36Sopenharmony_ci	efi_system_table_t *systab;
8562306a36Sopenharmony_ci	size_t table_size;
8662306a36Sopenharmony_ci	int retval;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	systab = early_memremap_ro(efi_system_table, sizeof(efi_system_table_t));
8962306a36Sopenharmony_ci	if (systab == NULL) {
9062306a36Sopenharmony_ci		pr_warn("Unable to map EFI system table.\n");
9162306a36Sopenharmony_ci		return -ENOMEM;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	set_bit(EFI_BOOT, &efi.flags);
9562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_64BIT))
9662306a36Sopenharmony_ci		set_bit(EFI_64BIT, &efi.flags);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	retval = efi_systab_check_header(&systab->hdr);
9962306a36Sopenharmony_ci	if (retval)
10062306a36Sopenharmony_ci		goto out;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	efi.runtime = systab->runtime;
10362306a36Sopenharmony_ci	efi.runtime_version = systab->hdr.revision;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	efi_systab_report_header(&systab->hdr, efi_to_phys(systab->fw_vendor));
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	table_size = sizeof(efi_config_table_t) * systab->nr_tables;
10862306a36Sopenharmony_ci	config_tables = early_memremap_ro(efi_to_phys(systab->tables),
10962306a36Sopenharmony_ci					  table_size);
11062306a36Sopenharmony_ci	if (config_tables == NULL) {
11162306a36Sopenharmony_ci		pr_warn("Unable to map EFI config table array.\n");
11262306a36Sopenharmony_ci		retval = -ENOMEM;
11362306a36Sopenharmony_ci		goto out;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	retval = efi_config_parse_tables(config_tables, systab->nr_tables,
11662306a36Sopenharmony_ci					 efi_arch_tables);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	early_memunmap(config_tables, table_size);
11962306a36Sopenharmony_ciout:
12062306a36Sopenharmony_ci	early_memunmap(systab, sizeof(efi_system_table_t));
12162306a36Sopenharmony_ci	return retval;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * Return true for regions that can be used as System RAM.
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistatic __init int is_usable_memory(efi_memory_desc_t *md)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	switch (md->type) {
13062306a36Sopenharmony_ci	case EFI_LOADER_CODE:
13162306a36Sopenharmony_ci	case EFI_LOADER_DATA:
13262306a36Sopenharmony_ci	case EFI_ACPI_RECLAIM_MEMORY:
13362306a36Sopenharmony_ci	case EFI_BOOT_SERVICES_CODE:
13462306a36Sopenharmony_ci	case EFI_BOOT_SERVICES_DATA:
13562306a36Sopenharmony_ci	case EFI_CONVENTIONAL_MEMORY:
13662306a36Sopenharmony_ci	case EFI_PERSISTENT_MEMORY:
13762306a36Sopenharmony_ci		/*
13862306a36Sopenharmony_ci		 * According to the spec, these regions are no longer reserved
13962306a36Sopenharmony_ci		 * after calling ExitBootServices(). However, we can only use
14062306a36Sopenharmony_ci		 * them as System RAM if they can be mapped writeback cacheable.
14162306a36Sopenharmony_ci		 */
14262306a36Sopenharmony_ci		return (md->attribute & EFI_MEMORY_WB);
14362306a36Sopenharmony_ci	default:
14462306a36Sopenharmony_ci		break;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci	return false;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic __init void reserve_regions(void)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	efi_memory_desc_t *md;
15262306a36Sopenharmony_ci	u64 paddr, npages, size;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (efi_enabled(EFI_DBG))
15562306a36Sopenharmony_ci		pr_info("Processing EFI memory map:\n");
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/*
15862306a36Sopenharmony_ci	 * Discard memblocks discovered so far: if there are any at this
15962306a36Sopenharmony_ci	 * point, they originate from memory nodes in the DT, and UEFI
16062306a36Sopenharmony_ci	 * uses its own memory map instead.
16162306a36Sopenharmony_ci	 */
16262306a36Sopenharmony_ci	memblock_dump_all();
16362306a36Sopenharmony_ci	memblock_remove(0, PHYS_ADDR_MAX);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	for_each_efi_memory_desc(md) {
16662306a36Sopenharmony_ci		paddr = md->phys_addr;
16762306a36Sopenharmony_ci		npages = md->num_pages;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		if (efi_enabled(EFI_DBG)) {
17062306a36Sopenharmony_ci			char buf[64];
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci			pr_info("  0x%012llx-0x%012llx %s\n",
17362306a36Sopenharmony_ci				paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
17462306a36Sopenharmony_ci				efi_md_typeattr_format(buf, sizeof(buf), md));
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		memrange_efi_to_native(&paddr, &npages);
17862306a36Sopenharmony_ci		size = npages << PAGE_SHIFT;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		if (is_memory(md)) {
18162306a36Sopenharmony_ci			/*
18262306a36Sopenharmony_ci			 * Special purpose memory is 'soft reserved', which
18362306a36Sopenharmony_ci			 * means it is set aside initially. Don't add a memblock
18462306a36Sopenharmony_ci			 * for it now so that it can be hotplugged back in or
18562306a36Sopenharmony_ci			 * be assigned to the dax driver after boot.
18662306a36Sopenharmony_ci			 */
18762306a36Sopenharmony_ci			if (efi_soft_reserve_enabled() &&
18862306a36Sopenharmony_ci			    (md->attribute & EFI_MEMORY_SP))
18962306a36Sopenharmony_ci				continue;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci			early_init_dt_add_memory_arch(paddr, size);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci			if (!is_usable_memory(md))
19462306a36Sopenharmony_ci				memblock_mark_nomap(paddr, size);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci			/* keep ACPI reclaim memory intact for kexec etc. */
19762306a36Sopenharmony_ci			if (md->type == EFI_ACPI_RECLAIM_MEMORY)
19862306a36Sopenharmony_ci				memblock_reserve(paddr, size);
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_civoid __init efi_init(void)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct efi_memory_map_data data;
20662306a36Sopenharmony_ci	u64 efi_system_table;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Grab UEFI information placed in FDT by stub */
20962306a36Sopenharmony_ci	efi_system_table = efi_get_fdt_params(&data);
21062306a36Sopenharmony_ci	if (!efi_system_table)
21162306a36Sopenharmony_ci		return;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (efi_memmap_init_early(&data) < 0) {
21462306a36Sopenharmony_ci		/*
21562306a36Sopenharmony_ci		* If we are booting via UEFI, the UEFI memory map is the only
21662306a36Sopenharmony_ci		* description of memory we have, so there is little point in
21762306a36Sopenharmony_ci		* proceeding if we cannot access it.
21862306a36Sopenharmony_ci		*/
21962306a36Sopenharmony_ci		panic("Unable to map EFI memory map.\n");
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	WARN(efi.memmap.desc_version != 1,
22362306a36Sopenharmony_ci	     "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
22462306a36Sopenharmony_ci	      efi.memmap.desc_version);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (uefi_init(efi_system_table) < 0) {
22762306a36Sopenharmony_ci		efi_memmap_unmap();
22862306a36Sopenharmony_ci		return;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	reserve_regions();
23262306a36Sopenharmony_ci	/*
23362306a36Sopenharmony_ci	 * For memblock manipulation, the cap should come after the memblock_add().
23462306a36Sopenharmony_ci	 * And now, memblock is fully populated, it is time to do capping.
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci	early_init_dt_check_for_usable_mem_range();
23762306a36Sopenharmony_ci	efi_find_mirror();
23862306a36Sopenharmony_ci	efi_esrt_init();
23962306a36Sopenharmony_ci	efi_mokvar_table_init();
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	memblock_reserve(data.phys_map & PAGE_MASK,
24262306a36Sopenharmony_ci			 PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	init_screen_info();
24562306a36Sopenharmony_ci}
246