18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "efi: " fmt
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/module.h>
68c2ecf20Sopenharmony_ci#include <linux/init.h>
78c2ecf20Sopenharmony_ci#include <linux/efi.h>
88c2ecf20Sopenharmony_ci#include <linux/libfdt.h>
98c2ecf20Sopenharmony_ci#include <linux/of_fdt.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cienum {
148c2ecf20Sopenharmony_ci	SYSTAB,
158c2ecf20Sopenharmony_ci	MMBASE,
168c2ecf20Sopenharmony_ci	MMSIZE,
178c2ecf20Sopenharmony_ci	DCSIZE,
188c2ecf20Sopenharmony_ci	DCVERS,
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	PARAMCOUNT
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic __initconst const char name[][22] = {
248c2ecf20Sopenharmony_ci	[SYSTAB] = "System Table         ",
258c2ecf20Sopenharmony_ci	[MMBASE] = "MemMap Address       ",
268c2ecf20Sopenharmony_ci	[MMSIZE] = "MemMap Size          ",
278c2ecf20Sopenharmony_ci	[DCSIZE] = "MemMap Desc. Size    ",
288c2ecf20Sopenharmony_ci	[DCVERS] = "MemMap Desc. Version ",
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic __initconst const struct {
328c2ecf20Sopenharmony_ci	const char	path[17];
338c2ecf20Sopenharmony_ci	const char	params[PARAMCOUNT][26];
348c2ecf20Sopenharmony_ci} dt_params[] = {
358c2ecf20Sopenharmony_ci	{
368c2ecf20Sopenharmony_ci#ifdef CONFIG_XEN    //  <-------17------>
378c2ecf20Sopenharmony_ci		.path = "/hypervisor/uefi",
388c2ecf20Sopenharmony_ci		.params = {
398c2ecf20Sopenharmony_ci			[SYSTAB] = "xen,uefi-system-table",
408c2ecf20Sopenharmony_ci			[MMBASE] = "xen,uefi-mmap-start",
418c2ecf20Sopenharmony_ci			[MMSIZE] = "xen,uefi-mmap-size",
428c2ecf20Sopenharmony_ci			[DCSIZE] = "xen,uefi-mmap-desc-size",
438c2ecf20Sopenharmony_ci			[DCVERS] = "xen,uefi-mmap-desc-ver",
448c2ecf20Sopenharmony_ci		}
458c2ecf20Sopenharmony_ci	}, {
468c2ecf20Sopenharmony_ci#endif
478c2ecf20Sopenharmony_ci		.path = "/chosen",
488c2ecf20Sopenharmony_ci		.params = {	//  <-----------26----------->
498c2ecf20Sopenharmony_ci			[SYSTAB] = "linux,uefi-system-table",
508c2ecf20Sopenharmony_ci			[MMBASE] = "linux,uefi-mmap-start",
518c2ecf20Sopenharmony_ci			[MMSIZE] = "linux,uefi-mmap-size",
528c2ecf20Sopenharmony_ci			[DCSIZE] = "linux,uefi-mmap-desc-size",
538c2ecf20Sopenharmony_ci			[DCVERS] = "linux,uefi-mmap-desc-ver",
548c2ecf20Sopenharmony_ci		}
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
598c2ecf20Sopenharmony_ci				   const char *rname, void *var, int size)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	const void *prop;
628c2ecf20Sopenharmony_ci	int len;
638c2ecf20Sopenharmony_ci	u64 val;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	prop = fdt_getprop(fdt, node, pname, &len);
668c2ecf20Sopenharmony_ci	if (!prop)
678c2ecf20Sopenharmony_ci		return 1;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (size == 8)
728c2ecf20Sopenharmony_ci		*(u64 *)var = val;
738c2ecf20Sopenharmony_ci	else
748c2ecf20Sopenharmony_ci		*(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (efi_enabled(EFI_DBG))
778c2ecf20Sopenharmony_ci		pr_info("  %s: 0x%0*llx\n", rname, size * 2, val);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciu64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	const void *fdt = initial_boot_params;
858c2ecf20Sopenharmony_ci	unsigned long systab;
868c2ecf20Sopenharmony_ci	int i, j, node;
878c2ecf20Sopenharmony_ci	struct {
888c2ecf20Sopenharmony_ci		void	*var;
898c2ecf20Sopenharmony_ci		int	size;
908c2ecf20Sopenharmony_ci	} target[] = {
918c2ecf20Sopenharmony_ci		[SYSTAB] = { &systab,		sizeof(systab) },
928c2ecf20Sopenharmony_ci		[MMBASE] = { &mm->phys_map,	sizeof(mm->phys_map) },
938c2ecf20Sopenharmony_ci		[MMSIZE] = { &mm->size,		sizeof(mm->size) },
948c2ecf20Sopenharmony_ci		[DCSIZE] = { &mm->desc_size,	sizeof(mm->desc_size) },
958c2ecf20Sopenharmony_ci		[DCVERS] = { &mm->desc_version,	sizeof(mm->desc_version) },
968c2ecf20Sopenharmony_ci	};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
998c2ecf20Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (!fdt)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
1058c2ecf20Sopenharmony_ci		node = fdt_path_offset(fdt, dt_params[i].path);
1068c2ecf20Sopenharmony_ci		if (node < 0)
1078c2ecf20Sopenharmony_ci			continue;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		if (efi_enabled(EFI_DBG))
1108c2ecf20Sopenharmony_ci			pr_info("Getting UEFI parameters from %s in DT:\n",
1118c2ecf20Sopenharmony_ci				dt_params[i].path);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(target); j++) {
1148c2ecf20Sopenharmony_ci			const char *pname = dt_params[i].params[j];
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci			if (!efi_get_fdt_prop(fdt, node, pname, name[j],
1178c2ecf20Sopenharmony_ci					      target[j].var, target[j].size))
1188c2ecf20Sopenharmony_ci				continue;
1198c2ecf20Sopenharmony_ci			if (!j)
1208c2ecf20Sopenharmony_ci				goto notfound;
1218c2ecf20Sopenharmony_ci			pr_err("Can't find property '%s' in DT!\n", pname);
1228c2ecf20Sopenharmony_ci			return 0;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci		return systab;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_cinotfound:
1278c2ecf20Sopenharmony_ci	pr_info("UEFI not found.\n");
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
130