1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #define pr_fmt(fmt) "efi: " fmt
4 
5 #include <linux/module.h>
6 #include <linux/init.h>
7 #include <linux/efi.h>
8 #include <linux/libfdt.h>
9 #include <linux/of_fdt.h>
10 
11 #include <asm/unaligned.h>
12 
13 enum {
14 	SYSTAB,
15 	MMBASE,
16 	MMSIZE,
17 	DCSIZE,
18 	DCVERS,
19 
20 	PARAMCOUNT
21 };
22 
23 static __initconst const char name[][22] = {
24 	[SYSTAB] = "System Table         ",
25 	[MMBASE] = "MemMap Address       ",
26 	[MMSIZE] = "MemMap Size          ",
27 	[DCSIZE] = "MemMap Desc. Size    ",
28 	[DCVERS] = "MemMap Desc. Version ",
29 };
30 
31 static __initconst const struct {
32 	const char	path[17];
33 	const char	params[PARAMCOUNT][26];
34 } dt_params[] = {
35 	{
36 #ifdef CONFIG_XEN    //  <-------17------>
37 		.path = "/hypervisor/uefi",
38 		.params = {
39 			[SYSTAB] = "xen,uefi-system-table",
40 			[MMBASE] = "xen,uefi-mmap-start",
41 			[MMSIZE] = "xen,uefi-mmap-size",
42 			[DCSIZE] = "xen,uefi-mmap-desc-size",
43 			[DCVERS] = "xen,uefi-mmap-desc-ver",
44 		}
45 	}, {
46 #endif
47 		.path = "/chosen",
48 		.params = {	//  <-----------26----------->
49 			[SYSTAB] = "linux,uefi-system-table",
50 			[MMBASE] = "linux,uefi-mmap-start",
51 			[MMSIZE] = "linux,uefi-mmap-size",
52 			[DCSIZE] = "linux,uefi-mmap-desc-size",
53 			[DCVERS] = "linux,uefi-mmap-desc-ver",
54 		}
55 	}
56 };
57 
efi_get_fdt_prop(const void * fdt,int node,const char * pname,const char * rname,void * var,int size)58 static int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
59 				   const char *rname, void *var, int size)
60 {
61 	const void *prop;
62 	int len;
63 	u64 val;
64 
65 	prop = fdt_getprop(fdt, node, pname, &len);
66 	if (!prop)
67 		return 1;
68 
69 	val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
70 
71 	if (size == 8)
72 		*(u64 *)var = val;
73 	else
74 		*(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate
75 
76 	if (efi_enabled(EFI_DBG))
77 		pr_info("  %s: 0x%0*llx\n", rname, size * 2, val);
78 
79 	return 0;
80 }
81 
efi_get_fdt_params(struct efi_memory_map_data * mm)82 u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
83 {
84 	const void *fdt = initial_boot_params;
85 	unsigned long systab;
86 	int i, j, node;
87 	struct {
88 		void	*var;
89 		int	size;
90 	} target[] = {
91 		[SYSTAB] = { &systab,		sizeof(systab) },
92 		[MMBASE] = { &mm->phys_map,	sizeof(mm->phys_map) },
93 		[MMSIZE] = { &mm->size,		sizeof(mm->size) },
94 		[DCSIZE] = { &mm->desc_size,	sizeof(mm->desc_size) },
95 		[DCVERS] = { &mm->desc_version,	sizeof(mm->desc_version) },
96 	};
97 
98 	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
99 	BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
100 
101 	if (!fdt)
102 		return 0;
103 
104 	for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
105 		node = fdt_path_offset(fdt, dt_params[i].path);
106 		if (node < 0)
107 			continue;
108 
109 		if (efi_enabled(EFI_DBG))
110 			pr_info("Getting UEFI parameters from %s in DT:\n",
111 				dt_params[i].path);
112 
113 		for (j = 0; j < ARRAY_SIZE(target); j++) {
114 			const char *pname = dt_params[i].params[j];
115 
116 			if (!efi_get_fdt_prop(fdt, node, pname, name[j],
117 					      target[j].var, target[j].size))
118 				continue;
119 			if (!j)
120 				goto notfound;
121 			pr_err("Can't find property '%s' in DT!\n", pname);
122 			return 0;
123 		}
124 		return systab;
125 	}
126 notfound:
127 	pr_info("UEFI not found.\n");
128 	return 0;
129 }
130