| // SPDX-License-Identifier: GPL-2.0-only | 
 |  | 
 | #define pr_fmt(fmt) "efi: " fmt | 
 |  | 
 | #include <linux/module.h> | 
 | #include <linux/init.h> | 
 | #include <linux/efi.h> | 
 | #include <linux/libfdt.h> | 
 | #include <linux/of_fdt.h> | 
 |  | 
 | #include <linux/unaligned.h> | 
 |  | 
 | enum { | 
 | 	SYSTAB, | 
 | 	MMBASE, | 
 | 	MMSIZE, | 
 | 	DCSIZE, | 
 | 	DCVERS, | 
 |  | 
 | 	PARAMCOUNT | 
 | }; | 
 |  | 
 | static __initconst const char name[][22] = { | 
 | 	[SYSTAB] = "System Table         ", | 
 | 	[MMBASE] = "MemMap Address       ", | 
 | 	[MMSIZE] = "MemMap Size          ", | 
 | 	[DCSIZE] = "MemMap Desc. Size    ", | 
 | 	[DCVERS] = "MemMap Desc. Version ", | 
 | }; | 
 |  | 
 | static __initconst const struct { | 
 | 	const char	path[17]; | 
 | 	u8		paravirt; | 
 | 	const char	params[PARAMCOUNT][26]; | 
 | } dt_params[] = { | 
 | 	{ | 
 | #ifdef CONFIG_XEN    //  <-------17------> | 
 | 		.path = "/hypervisor/uefi", | 
 | 		.paravirt = 1, | 
 | 		.params = { | 
 | 			[SYSTAB] = "xen,uefi-system-table", | 
 | 			[MMBASE] = "xen,uefi-mmap-start", | 
 | 			[MMSIZE] = "xen,uefi-mmap-size", | 
 | 			[DCSIZE] = "xen,uefi-mmap-desc-size", | 
 | 			[DCVERS] = "xen,uefi-mmap-desc-ver", | 
 | 		} | 
 | 	}, { | 
 | #endif | 
 | 		.path = "/chosen", | 
 | 		.params = {	//  <-----------26-----------> | 
 | 			[SYSTAB] = "linux,uefi-system-table", | 
 | 			[MMBASE] = "linux,uefi-mmap-start", | 
 | 			[MMSIZE] = "linux,uefi-mmap-size", | 
 | 			[DCSIZE] = "linux,uefi-mmap-desc-size", | 
 | 			[DCVERS] = "linux,uefi-mmap-desc-ver", | 
 | 		} | 
 | 	} | 
 | }; | 
 |  | 
 | static int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname, | 
 | 				   const char *rname, void *var, int size) | 
 | { | 
 | 	const void *prop; | 
 | 	int len; | 
 | 	u64 val; | 
 |  | 
 | 	prop = fdt_getprop(fdt, node, pname, &len); | 
 | 	if (!prop) | 
 | 		return 1; | 
 |  | 
 | 	val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop); | 
 |  | 
 | 	if (size == 8) | 
 | 		*(u64 *)var = val; | 
 | 	else | 
 | 		*(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate | 
 |  | 
 | 	if (efi_enabled(EFI_DBG)) | 
 | 		pr_info("  %s: 0x%0*llx\n", rname, size * 2, val); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm) | 
 | { | 
 | 	const void *fdt = initial_boot_params; | 
 | 	unsigned long systab; | 
 | 	int i, j, node; | 
 | 	struct { | 
 | 		void	*var; | 
 | 		int	size; | 
 | 	} target[] = { | 
 | 		[SYSTAB] = { &systab,		sizeof(systab) }, | 
 | 		[MMBASE] = { &mm->phys_map,	sizeof(mm->phys_map) }, | 
 | 		[MMSIZE] = { &mm->size,		sizeof(mm->size) }, | 
 | 		[DCSIZE] = { &mm->desc_size,	sizeof(mm->desc_size) }, | 
 | 		[DCVERS] = { &mm->desc_version,	sizeof(mm->desc_version) }, | 
 | 	}; | 
 |  | 
 | 	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name)); | 
 | 	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params)); | 
 |  | 
 | 	if (!fdt) | 
 | 		return 0; | 
 |  | 
 | 	for (i = 0; i < ARRAY_SIZE(dt_params); i++) { | 
 | 		node = fdt_path_offset(fdt, dt_params[i].path); | 
 | 		if (node < 0) | 
 | 			continue; | 
 |  | 
 | 		if (efi_enabled(EFI_DBG)) | 
 | 			pr_info("Getting UEFI parameters from %s in DT:\n", | 
 | 				dt_params[i].path); | 
 |  | 
 | 		for (j = 0; j < ARRAY_SIZE(target); j++) { | 
 | 			const char *pname = dt_params[i].params[j]; | 
 |  | 
 | 			if (!efi_get_fdt_prop(fdt, node, pname, name[j], | 
 | 					      target[j].var, target[j].size)) | 
 | 				continue; | 
 | 			if (!j) | 
 | 				goto notfound; | 
 | 			pr_err("Can't find property '%s' in DT!\n", pname); | 
 | 			return 0; | 
 | 		} | 
 | 		if (dt_params[i].paravirt) | 
 | 			set_bit(EFI_PARAVIRT, &efi.flags); | 
 | 		return systab; | 
 | 	} | 
 | notfound: | 
 | 	pr_info("UEFI not found.\n"); | 
 | 	return 0; | 
 | } |