162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#define pr_fmt(fmt) "efi: " fmt
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci#include <linux/init.h>
762306a36Sopenharmony_ci#include <linux/efi.h>
862306a36Sopenharmony_ci#include <linux/libfdt.h>
962306a36Sopenharmony_ci#include <linux/of_fdt.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/unaligned.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cienum {
1462306a36Sopenharmony_ci	SYSTAB,
1562306a36Sopenharmony_ci	MMBASE,
1662306a36Sopenharmony_ci	MMSIZE,
1762306a36Sopenharmony_ci	DCSIZE,
1862306a36Sopenharmony_ci	DCVERS,
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	PARAMCOUNT
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic __initconst const char name[][22] = {
2462306a36Sopenharmony_ci	[SYSTAB] = "System Table         ",
2562306a36Sopenharmony_ci	[MMBASE] = "MemMap Address       ",
2662306a36Sopenharmony_ci	[MMSIZE] = "MemMap Size          ",
2762306a36Sopenharmony_ci	[DCSIZE] = "MemMap Desc. Size    ",
2862306a36Sopenharmony_ci	[DCVERS] = "MemMap Desc. Version ",
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic __initconst const struct {
3262306a36Sopenharmony_ci	const char	path[17];
3362306a36Sopenharmony_ci	u8		paravirt;
3462306a36Sopenharmony_ci	const char	params[PARAMCOUNT][26];
3562306a36Sopenharmony_ci} dt_params[] = {
3662306a36Sopenharmony_ci	{
3762306a36Sopenharmony_ci#ifdef CONFIG_XEN    //  <-------17------>
3862306a36Sopenharmony_ci		.path = "/hypervisor/uefi",
3962306a36Sopenharmony_ci		.paravirt = 1,
4062306a36Sopenharmony_ci		.params = {
4162306a36Sopenharmony_ci			[SYSTAB] = "xen,uefi-system-table",
4262306a36Sopenharmony_ci			[MMBASE] = "xen,uefi-mmap-start",
4362306a36Sopenharmony_ci			[MMSIZE] = "xen,uefi-mmap-size",
4462306a36Sopenharmony_ci			[DCSIZE] = "xen,uefi-mmap-desc-size",
4562306a36Sopenharmony_ci			[DCVERS] = "xen,uefi-mmap-desc-ver",
4662306a36Sopenharmony_ci		}
4762306a36Sopenharmony_ci	}, {
4862306a36Sopenharmony_ci#endif
4962306a36Sopenharmony_ci		.path = "/chosen",
5062306a36Sopenharmony_ci		.params = {	//  <-----------26----------->
5162306a36Sopenharmony_ci			[SYSTAB] = "linux,uefi-system-table",
5262306a36Sopenharmony_ci			[MMBASE] = "linux,uefi-mmap-start",
5362306a36Sopenharmony_ci			[MMSIZE] = "linux,uefi-mmap-size",
5462306a36Sopenharmony_ci			[DCSIZE] = "linux,uefi-mmap-desc-size",
5562306a36Sopenharmony_ci			[DCVERS] = "linux,uefi-mmap-desc-ver",
5662306a36Sopenharmony_ci		}
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
6162306a36Sopenharmony_ci				   const char *rname, void *var, int size)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	const void *prop;
6462306a36Sopenharmony_ci	int len;
6562306a36Sopenharmony_ci	u64 val;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	prop = fdt_getprop(fdt, node, pname, &len);
6862306a36Sopenharmony_ci	if (!prop)
6962306a36Sopenharmony_ci		return 1;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (size == 8)
7462306a36Sopenharmony_ci		*(u64 *)var = val;
7562306a36Sopenharmony_ci	else
7662306a36Sopenharmony_ci		*(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (efi_enabled(EFI_DBG))
7962306a36Sopenharmony_ci		pr_info("  %s: 0x%0*llx\n", rname, size * 2, val);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return 0;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ciu64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	const void *fdt = initial_boot_params;
8762306a36Sopenharmony_ci	unsigned long systab;
8862306a36Sopenharmony_ci	int i, j, node;
8962306a36Sopenharmony_ci	struct {
9062306a36Sopenharmony_ci		void	*var;
9162306a36Sopenharmony_ci		int	size;
9262306a36Sopenharmony_ci	} target[] = {
9362306a36Sopenharmony_ci		[SYSTAB] = { &systab,		sizeof(systab) },
9462306a36Sopenharmony_ci		[MMBASE] = { &mm->phys_map,	sizeof(mm->phys_map) },
9562306a36Sopenharmony_ci		[MMSIZE] = { &mm->size,		sizeof(mm->size) },
9662306a36Sopenharmony_ci		[DCSIZE] = { &mm->desc_size,	sizeof(mm->desc_size) },
9762306a36Sopenharmony_ci		[DCVERS] = { &mm->desc_version,	sizeof(mm->desc_version) },
9862306a36Sopenharmony_ci	};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
10162306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (!fdt)
10462306a36Sopenharmony_ci		return 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
10762306a36Sopenharmony_ci		node = fdt_path_offset(fdt, dt_params[i].path);
10862306a36Sopenharmony_ci		if (node < 0)
10962306a36Sopenharmony_ci			continue;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		if (efi_enabled(EFI_DBG))
11262306a36Sopenharmony_ci			pr_info("Getting UEFI parameters from %s in DT:\n",
11362306a36Sopenharmony_ci				dt_params[i].path);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(target); j++) {
11662306a36Sopenharmony_ci			const char *pname = dt_params[i].params[j];
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci			if (!efi_get_fdt_prop(fdt, node, pname, name[j],
11962306a36Sopenharmony_ci					      target[j].var, target[j].size))
12062306a36Sopenharmony_ci				continue;
12162306a36Sopenharmony_ci			if (!j)
12262306a36Sopenharmony_ci				goto notfound;
12362306a36Sopenharmony_ci			pr_err("Can't find property '%s' in DT!\n", pname);
12462306a36Sopenharmony_ci			return 0;
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci		if (dt_params[i].paravirt)
12762306a36Sopenharmony_ci			set_bit(EFI_PARAVIRT, &efi.flags);
12862306a36Sopenharmony_ci		return systab;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_cinotfound:
13162306a36Sopenharmony_ci	pr_info("UEFI not found.\n");
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
134