]>
Commit | Line | Data |
---|---|---|
a9499fa7 TG |
1 | /* |
2 | * efi.c - EFI subsystem | |
3 | * | |
4 | * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> | |
5 | * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> | |
6 | * Copyright (C) 2013 Tom Gundersen <teg@jklm.no> | |
7 | * | |
8 | * This code registers /sys/firmware/efi{,/efivars} when EFI is supported, | |
9 | * allowing the efivarfs to be mounted or the efivars module to be loaded. | |
10 | * The existance of /sys/firmware/efi may also be used by userspace to | |
11 | * determine that the system supports EFI. | |
12 | * | |
13 | * This file is released under the GPLv2. | |
14 | */ | |
15 | ||
272686bf LL |
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
17 | ||
a9499fa7 TG |
18 | #include <linux/kobject.h> |
19 | #include <linux/module.h> | |
20 | #include <linux/init.h> | |
21 | #include <linux/device.h> | |
22 | #include <linux/efi.h> | |
0302f71c MS |
23 | #include <linux/of.h> |
24 | #include <linux/of_fdt.h> | |
272686bf | 25 | #include <linux/io.h> |
28d54022 | 26 | #include <linux/platform_device.h> |
272686bf LL |
27 | |
28 | struct efi __read_mostly efi = { | |
29 | .mps = EFI_INVALID_TABLE_ADDR, | |
30 | .acpi = EFI_INVALID_TABLE_ADDR, | |
31 | .acpi20 = EFI_INVALID_TABLE_ADDR, | |
32 | .smbios = EFI_INVALID_TABLE_ADDR, | |
e1ccbbc9 | 33 | .smbios3 = EFI_INVALID_TABLE_ADDR, |
272686bf LL |
34 | .sal_systab = EFI_INVALID_TABLE_ADDR, |
35 | .boot_info = EFI_INVALID_TABLE_ADDR, | |
36 | .hcdp = EFI_INVALID_TABLE_ADDR, | |
37 | .uga = EFI_INVALID_TABLE_ADDR, | |
38 | .uv_systab = EFI_INVALID_TABLE_ADDR, | |
a0998eb1 DY |
39 | .fw_vendor = EFI_INVALID_TABLE_ADDR, |
40 | .runtime = EFI_INVALID_TABLE_ADDR, | |
41 | .config_table = EFI_INVALID_TABLE_ADDR, | |
0bb54905 | 42 | .esrt = EFI_INVALID_TABLE_ADDR, |
272686bf LL |
43 | }; |
44 | EXPORT_SYMBOL(efi); | |
a9499fa7 | 45 | |
b2e0a54a DY |
46 | static bool disable_runtime; |
47 | static int __init setup_noefi(char *arg) | |
48 | { | |
49 | disable_runtime = true; | |
50 | return 0; | |
51 | } | |
52 | early_param("noefi", setup_noefi); | |
53 | ||
54 | bool efi_runtime_disabled(void) | |
55 | { | |
56 | return disable_runtime; | |
57 | } | |
58 | ||
5ae3683c DY |
59 | static int __init parse_efi_cmdline(char *str) |
60 | { | |
61 | if (parse_option_str(str, "noruntime")) | |
62 | disable_runtime = true; | |
63 | ||
64 | return 0; | |
65 | } | |
66 | early_param("efi", parse_efi_cmdline); | |
67 | ||
0bb54905 | 68 | struct kobject *efi_kobj; |
a9499fa7 TG |
69 | static struct kobject *efivars_kobj; |
70 | ||
71 | /* | |
72 | * Let's not leave out systab information that snuck into | |
73 | * the efivars driver | |
74 | */ | |
75 | static ssize_t systab_show(struct kobject *kobj, | |
76 | struct kobj_attribute *attr, char *buf) | |
77 | { | |
78 | char *str = buf; | |
79 | ||
80 | if (!kobj || !buf) | |
81 | return -EINVAL; | |
82 | ||
83 | if (efi.mps != EFI_INVALID_TABLE_ADDR) | |
84 | str += sprintf(str, "MPS=0x%lx\n", efi.mps); | |
85 | if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) | |
86 | str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20); | |
87 | if (efi.acpi != EFI_INVALID_TABLE_ADDR) | |
88 | str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); | |
b119fe08 JD |
89 | /* |
90 | * If both SMBIOS and SMBIOS3 entry points are implemented, the | |
91 | * SMBIOS3 entry point shall be preferred, so we list it first to | |
92 | * let applications stop parsing after the first match. | |
93 | */ | |
e1ccbbc9 AB |
94 | if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) |
95 | str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3); | |
b119fe08 JD |
96 | if (efi.smbios != EFI_INVALID_TABLE_ADDR) |
97 | str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); | |
a9499fa7 TG |
98 | if (efi.hcdp != EFI_INVALID_TABLE_ADDR) |
99 | str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); | |
100 | if (efi.boot_info != EFI_INVALID_TABLE_ADDR) | |
101 | str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info); | |
102 | if (efi.uga != EFI_INVALID_TABLE_ADDR) | |
103 | str += sprintf(str, "UGA=0x%lx\n", efi.uga); | |
104 | ||
105 | return str - buf; | |
106 | } | |
107 | ||
108 | static struct kobj_attribute efi_attr_systab = | |
109 | __ATTR(systab, 0400, systab_show, NULL); | |
110 | ||
a0998eb1 DY |
111 | #define EFI_FIELD(var) efi.var |
112 | ||
113 | #define EFI_ATTR_SHOW(name) \ | |
114 | static ssize_t name##_show(struct kobject *kobj, \ | |
115 | struct kobj_attribute *attr, char *buf) \ | |
116 | { \ | |
117 | return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \ | |
118 | } | |
119 | ||
120 | EFI_ATTR_SHOW(fw_vendor); | |
121 | EFI_ATTR_SHOW(runtime); | |
122 | EFI_ATTR_SHOW(config_table); | |
123 | ||
2859dff9 SM |
124 | static ssize_t fw_platform_size_show(struct kobject *kobj, |
125 | struct kobj_attribute *attr, char *buf) | |
126 | { | |
127 | return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32); | |
128 | } | |
129 | ||
a0998eb1 DY |
130 | static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor); |
131 | static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime); | |
132 | static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table); | |
2859dff9 SM |
133 | static struct kobj_attribute efi_attr_fw_platform_size = |
134 | __ATTR_RO(fw_platform_size); | |
a0998eb1 | 135 | |
a9499fa7 TG |
136 | static struct attribute *efi_subsys_attrs[] = { |
137 | &efi_attr_systab.attr, | |
a0998eb1 DY |
138 | &efi_attr_fw_vendor.attr, |
139 | &efi_attr_runtime.attr, | |
140 | &efi_attr_config_table.attr, | |
2859dff9 | 141 | &efi_attr_fw_platform_size.attr, |
a0998eb1 | 142 | NULL, |
a9499fa7 TG |
143 | }; |
144 | ||
a0998eb1 DY |
145 | static umode_t efi_attr_is_visible(struct kobject *kobj, |
146 | struct attribute *attr, int n) | |
147 | { | |
9f27bc54 DK |
148 | if (attr == &efi_attr_fw_vendor.attr) { |
149 | if (efi_enabled(EFI_PARAVIRT) || | |
150 | efi.fw_vendor == EFI_INVALID_TABLE_ADDR) | |
151 | return 0; | |
152 | } else if (attr == &efi_attr_runtime.attr) { | |
153 | if (efi.runtime == EFI_INVALID_TABLE_ADDR) | |
154 | return 0; | |
155 | } else if (attr == &efi_attr_config_table.attr) { | |
156 | if (efi.config_table == EFI_INVALID_TABLE_ADDR) | |
157 | return 0; | |
158 | } | |
a0998eb1 | 159 | |
9f27bc54 | 160 | return attr->mode; |
a0998eb1 DY |
161 | } |
162 | ||
a9499fa7 TG |
163 | static struct attribute_group efi_subsys_attr_group = { |
164 | .attrs = efi_subsys_attrs, | |
a0998eb1 | 165 | .is_visible = efi_attr_is_visible, |
a9499fa7 TG |
166 | }; |
167 | ||
168 | static struct efivars generic_efivars; | |
169 | static struct efivar_operations generic_ops; | |
170 | ||
171 | static int generic_ops_register(void) | |
172 | { | |
173 | generic_ops.get_variable = efi.get_variable; | |
174 | generic_ops.set_variable = efi.set_variable; | |
175 | generic_ops.get_next_variable = efi.get_next_variable; | |
a614e192 | 176 | generic_ops.query_variable_store = efi_query_variable_store; |
a9499fa7 TG |
177 | |
178 | return efivars_register(&generic_efivars, &generic_ops, efi_kobj); | |
179 | } | |
180 | ||
181 | static void generic_ops_unregister(void) | |
182 | { | |
183 | efivars_unregister(&generic_efivars); | |
184 | } | |
185 | ||
186 | /* | |
187 | * We register the efi subsystem with the firmware subsystem and the | |
188 | * efivars subsystem with the efi subsystem, if the system was booted with | |
189 | * EFI. | |
190 | */ | |
191 | static int __init efisubsys_init(void) | |
192 | { | |
193 | int error; | |
194 | ||
195 | if (!efi_enabled(EFI_BOOT)) | |
196 | return 0; | |
197 | ||
198 | /* We register the efi directory at /sys/firmware/efi */ | |
199 | efi_kobj = kobject_create_and_add("efi", firmware_kobj); | |
200 | if (!efi_kobj) { | |
201 | pr_err("efi: Firmware registration failed.\n"); | |
202 | return -ENOMEM; | |
203 | } | |
204 | ||
205 | error = generic_ops_register(); | |
206 | if (error) | |
207 | goto err_put; | |
208 | ||
209 | error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); | |
210 | if (error) { | |
211 | pr_err("efi: Sysfs attribute export failed with error %d.\n", | |
212 | error); | |
213 | goto err_unregister; | |
214 | } | |
215 | ||
926172d4 DY |
216 | error = efi_runtime_map_init(efi_kobj); |
217 | if (error) | |
218 | goto err_remove_group; | |
219 | ||
a9499fa7 TG |
220 | /* and the standard mountpoint for efivarfs */ |
221 | efivars_kobj = kobject_create_and_add("efivars", efi_kobj); | |
222 | if (!efivars_kobj) { | |
223 | pr_err("efivars: Subsystem registration failed.\n"); | |
224 | error = -ENOMEM; | |
225 | goto err_remove_group; | |
226 | } | |
227 | ||
228 | return 0; | |
229 | ||
230 | err_remove_group: | |
231 | sysfs_remove_group(efi_kobj, &efi_subsys_attr_group); | |
232 | err_unregister: | |
233 | generic_ops_unregister(); | |
234 | err_put: | |
235 | kobject_put(efi_kobj); | |
236 | return error; | |
237 | } | |
238 | ||
239 | subsys_initcall(efisubsys_init); | |
272686bf | 240 | |
0bb54905 PJ |
241 | /* |
242 | * Find the efi memory descriptor for a given physical address. Given a | |
243 | * physicall address, determine if it exists within an EFI Memory Map entry, | |
244 | * and if so, populate the supplied memory descriptor with the appropriate | |
245 | * data. | |
246 | */ | |
247 | int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) | |
248 | { | |
249 | struct efi_memory_map *map = efi.memmap; | |
250 | void *p, *e; | |
251 | ||
252 | if (!efi_enabled(EFI_MEMMAP)) { | |
253 | pr_err_once("EFI_MEMMAP is not enabled.\n"); | |
254 | return -EINVAL; | |
255 | } | |
256 | ||
257 | if (!map) { | |
258 | pr_err_once("efi.memmap is not set.\n"); | |
259 | return -EINVAL; | |
260 | } | |
261 | if (!out_md) { | |
262 | pr_err_once("out_md is null.\n"); | |
263 | return -EINVAL; | |
264 | } | |
265 | if (WARN_ON_ONCE(!map->phys_map)) | |
266 | return -EINVAL; | |
267 | if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0)) | |
268 | return -EINVAL; | |
269 | ||
270 | e = map->phys_map + map->nr_map * map->desc_size; | |
271 | for (p = map->phys_map; p < e; p += map->desc_size) { | |
272 | efi_memory_desc_t *md; | |
273 | u64 size; | |
274 | u64 end; | |
275 | ||
276 | /* | |
277 | * If a driver calls this after efi_free_boot_services, | |
278 | * ->map will be NULL, and the target may also not be mapped. | |
279 | * So just always get our own virtual map on the CPU. | |
280 | * | |
281 | */ | |
282 | md = early_memremap((phys_addr_t)p, sizeof (*md)); | |
283 | if (!md) { | |
284 | pr_err_once("early_memremap(%p, %zu) failed.\n", | |
285 | p, sizeof (*md)); | |
286 | return -ENOMEM; | |
287 | } | |
288 | ||
289 | if (!(md->attribute & EFI_MEMORY_RUNTIME) && | |
290 | md->type != EFI_BOOT_SERVICES_DATA && | |
291 | md->type != EFI_RUNTIME_SERVICES_DATA) { | |
292 | early_memunmap(md, sizeof (*md)); | |
293 | continue; | |
294 | } | |
295 | ||
296 | size = md->num_pages << EFI_PAGE_SHIFT; | |
297 | end = md->phys_addr + size; | |
298 | if (phys_addr >= md->phys_addr && phys_addr < end) { | |
299 | memcpy(out_md, md, sizeof(*out_md)); | |
300 | early_memunmap(md, sizeof (*md)); | |
301 | return 0; | |
302 | } | |
303 | ||
304 | early_memunmap(md, sizeof (*md)); | |
305 | } | |
306 | pr_err_once("requested map not found.\n"); | |
307 | return -ENOENT; | |
308 | } | |
309 | ||
310 | /* | |
311 | * Calculate the highest address of an efi memory descriptor. | |
312 | */ | |
313 | u64 __init efi_mem_desc_end(efi_memory_desc_t *md) | |
314 | { | |
315 | u64 size = md->num_pages << EFI_PAGE_SHIFT; | |
316 | u64 end = md->phys_addr + size; | |
317 | return end; | |
318 | } | |
272686bf | 319 | |
258f6fd7 LL |
320 | /* |
321 | * We can't ioremap data in EFI boot services RAM, because we've already mapped | |
322 | * it as RAM. So, look it up in the existing EFI memory map instead. Only | |
323 | * callable after efi_enter_virtual_mode and before efi_free_boot_services. | |
324 | */ | |
325 | void __iomem *efi_lookup_mapped_addr(u64 phys_addr) | |
326 | { | |
327 | struct efi_memory_map *map; | |
328 | void *p; | |
329 | map = efi.memmap; | |
330 | if (!map) | |
331 | return NULL; | |
332 | if (WARN_ON(!map->map)) | |
333 | return NULL; | |
334 | for (p = map->map; p < map->map_end; p += map->desc_size) { | |
335 | efi_memory_desc_t *md = p; | |
336 | u64 size = md->num_pages << EFI_PAGE_SHIFT; | |
337 | u64 end = md->phys_addr + size; | |
338 | if (!(md->attribute & EFI_MEMORY_RUNTIME) && | |
339 | md->type != EFI_BOOT_SERVICES_CODE && | |
340 | md->type != EFI_BOOT_SERVICES_DATA) | |
341 | continue; | |
342 | if (!md->virt_addr) | |
343 | continue; | |
344 | if (phys_addr >= md->phys_addr && phys_addr < end) { | |
345 | phys_addr += md->virt_addr - md->phys_addr; | |
346 | return (__force void __iomem *)(unsigned long)phys_addr; | |
347 | } | |
348 | } | |
349 | return NULL; | |
350 | } | |
351 | ||
272686bf LL |
352 | static __initdata efi_config_table_type_t common_tables[] = { |
353 | {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, | |
354 | {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, | |
355 | {HCDP_TABLE_GUID, "HCDP", &efi.hcdp}, | |
356 | {MPS_TABLE_GUID, "MPS", &efi.mps}, | |
357 | {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab}, | |
358 | {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, | |
e1ccbbc9 | 359 | {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3}, |
272686bf | 360 | {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, |
0bb54905 | 361 | {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt}, |
69e60841 | 362 | {NULL_GUID, NULL, NULL}, |
272686bf LL |
363 | }; |
364 | ||
365 | static __init int match_config_table(efi_guid_t *guid, | |
366 | unsigned long table, | |
367 | efi_config_table_type_t *table_types) | |
368 | { | |
272686bf LL |
369 | int i; |
370 | ||
371 | if (table_types) { | |
272686bf | 372 | for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { |
272686bf LL |
373 | if (!efi_guidcmp(*guid, table_types[i].guid)) { |
374 | *(table_types[i].ptr) = table; | |
375 | pr_cont(" %s=0x%lx ", | |
376 | table_types[i].name, table); | |
377 | return 1; | |
378 | } | |
379 | } | |
380 | } | |
381 | ||
382 | return 0; | |
383 | } | |
384 | ||
7bb68410 AB |
385 | int __init efi_config_parse_tables(void *config_tables, int count, int sz, |
386 | efi_config_table_type_t *arch_tables) | |
272686bf | 387 | { |
7bb68410 AB |
388 | void *tablep; |
389 | int i; | |
272686bf LL |
390 | |
391 | tablep = config_tables; | |
392 | pr_info(""); | |
7bb68410 | 393 | for (i = 0; i < count; i++) { |
272686bf LL |
394 | efi_guid_t guid; |
395 | unsigned long table; | |
396 | ||
397 | if (efi_enabled(EFI_64BIT)) { | |
398 | u64 table64; | |
399 | guid = ((efi_config_table_64_t *)tablep)->guid; | |
400 | table64 = ((efi_config_table_64_t *)tablep)->table; | |
401 | table = table64; | |
402 | #ifndef CONFIG_64BIT | |
403 | if (table64 >> 32) { | |
404 | pr_cont("\n"); | |
405 | pr_err("Table located above 4GB, disabling EFI.\n"); | |
272686bf LL |
406 | return -EINVAL; |
407 | } | |
408 | #endif | |
409 | } else { | |
410 | guid = ((efi_config_table_32_t *)tablep)->guid; | |
411 | table = ((efi_config_table_32_t *)tablep)->table; | |
412 | } | |
413 | ||
414 | if (!match_config_table(&guid, table, common_tables)) | |
415 | match_config_table(&guid, table, arch_tables); | |
416 | ||
417 | tablep += sz; | |
418 | } | |
419 | pr_cont("\n"); | |
0f8093a9 | 420 | set_bit(EFI_CONFIG_TABLES, &efi.flags); |
272686bf LL |
421 | return 0; |
422 | } | |
0302f71c | 423 | |
7bb68410 AB |
424 | int __init efi_config_init(efi_config_table_type_t *arch_tables) |
425 | { | |
426 | void *config_tables; | |
427 | int sz, ret; | |
428 | ||
429 | if (efi_enabled(EFI_64BIT)) | |
430 | sz = sizeof(efi_config_table_64_t); | |
431 | else | |
432 | sz = sizeof(efi_config_table_32_t); | |
433 | ||
434 | /* | |
435 | * Let's see what config tables the firmware passed to us. | |
436 | */ | |
437 | config_tables = early_memremap(efi.systab->tables, | |
438 | efi.systab->nr_tables * sz); | |
439 | if (config_tables == NULL) { | |
440 | pr_err("Could not map Configuration table!\n"); | |
441 | return -ENOMEM; | |
442 | } | |
443 | ||
444 | ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz, | |
445 | arch_tables); | |
446 | ||
447 | early_memunmap(config_tables, efi.systab->nr_tables * sz); | |
448 | return ret; | |
449 | } | |
450 | ||
28d54022 LCY |
451 | #ifdef CONFIG_EFI_VARS_MODULE |
452 | static int __init efi_load_efivars(void) | |
453 | { | |
454 | struct platform_device *pdev; | |
455 | ||
456 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) | |
457 | return 0; | |
458 | ||
459 | pdev = platform_device_register_simple("efivars", 0, NULL, 0); | |
460 | return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; | |
461 | } | |
462 | device_initcall(efi_load_efivars); | |
463 | #endif | |
464 | ||
0302f71c MS |
465 | #ifdef CONFIG_EFI_PARAMS_FROM_FDT |
466 | ||
467 | #define UEFI_PARAM(name, prop, field) \ | |
468 | { \ | |
469 | { name }, \ | |
470 | { prop }, \ | |
471 | offsetof(struct efi_fdt_params, field), \ | |
472 | FIELD_SIZEOF(struct efi_fdt_params, field) \ | |
473 | } | |
474 | ||
475 | static __initdata struct { | |
476 | const char name[32]; | |
477 | const char propname[32]; | |
478 | int offset; | |
479 | int size; | |
480 | } dt_params[] = { | |
481 | UEFI_PARAM("System Table", "linux,uefi-system-table", system_table), | |
482 | UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap), | |
483 | UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size), | |
484 | UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size), | |
485 | UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver) | |
486 | }; | |
487 | ||
488 | struct param_info { | |
489 | int verbose; | |
29e2435f | 490 | int found; |
0302f71c MS |
491 | void *params; |
492 | }; | |
493 | ||
494 | static int __init fdt_find_uefi_params(unsigned long node, const char *uname, | |
495 | int depth, void *data) | |
496 | { | |
497 | struct param_info *info = data; | |
6fb8cc82 CM |
498 | const void *prop; |
499 | void *dest; | |
0302f71c | 500 | u64 val; |
6fb8cc82 | 501 | int i, len; |
0302f71c | 502 | |
11629305 | 503 | if (depth != 1 || strcmp(uname, "chosen") != 0) |
0302f71c MS |
504 | return 0; |
505 | ||
0302f71c MS |
506 | for (i = 0; i < ARRAY_SIZE(dt_params); i++) { |
507 | prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len); | |
29e2435f | 508 | if (!prop) |
0302f71c | 509 | return 0; |
0302f71c | 510 | dest = info->params + dt_params[i].offset; |
29e2435f | 511 | info->found++; |
0302f71c MS |
512 | |
513 | val = of_read_number(prop, len / sizeof(u32)); | |
514 | ||
515 | if (dt_params[i].size == sizeof(u32)) | |
516 | *(u32 *)dest = val; | |
517 | else | |
518 | *(u64 *)dest = val; | |
519 | ||
520 | if (info->verbose) | |
521 | pr_info(" %s: 0x%0*llx\n", dt_params[i].name, | |
522 | dt_params[i].size * 2, val); | |
523 | } | |
524 | return 1; | |
525 | } | |
526 | ||
527 | int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose) | |
528 | { | |
529 | struct param_info info; | |
29e2435f CM |
530 | int ret; |
531 | ||
532 | pr_info("Getting EFI parameters from FDT:\n"); | |
0302f71c MS |
533 | |
534 | info.verbose = verbose; | |
29e2435f | 535 | info.found = 0; |
0302f71c MS |
536 | info.params = params; |
537 | ||
29e2435f CM |
538 | ret = of_scan_flat_dt(fdt_find_uefi_params, &info); |
539 | if (!info.found) | |
540 | pr_info("UEFI not found.\n"); | |
541 | else if (!ret) | |
542 | pr_err("Can't find '%s' in device tree!\n", | |
543 | dt_params[info.found].name); | |
544 | ||
545 | return ret; | |
0302f71c MS |
546 | } |
547 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ | |
98d2a6ca LE |
548 | |
549 | static __initdata char memory_type_name[][20] = { | |
550 | "Reserved", | |
551 | "Loader Code", | |
552 | "Loader Data", | |
553 | "Boot Code", | |
554 | "Boot Data", | |
555 | "Runtime Code", | |
556 | "Runtime Data", | |
557 | "Conventional Memory", | |
558 | "Unusable Memory", | |
559 | "ACPI Reclaim Memory", | |
560 | "ACPI Memory NVS", | |
561 | "Memory Mapped I/O", | |
562 | "MMIO Port Space", | |
563 | "PAL Code" | |
564 | }; | |
565 | ||
566 | char * __init efi_md_typeattr_format(char *buf, size_t size, | |
567 | const efi_memory_desc_t *md) | |
568 | { | |
569 | char *pos; | |
570 | int type_len; | |
571 | u64 attr; | |
572 | ||
573 | pos = buf; | |
574 | if (md->type >= ARRAY_SIZE(memory_type_name)) | |
575 | type_len = snprintf(pos, size, "[type=%u", md->type); | |
576 | else | |
577 | type_len = snprintf(pos, size, "[%-*s", | |
578 | (int)(sizeof(memory_type_name[0]) - 1), | |
579 | memory_type_name[md->type]); | |
580 | if (type_len >= size) | |
581 | return buf; | |
582 | ||
583 | pos += type_len; | |
584 | size -= type_len; | |
585 | ||
586 | attr = md->attribute; | |
587 | if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | | |
588 | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP | | |
589 | EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME)) | |
590 | snprintf(pos, size, "|attr=0x%016llx]", | |
591 | (unsigned long long)attr); | |
592 | else | |
593 | snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", | |
594 | attr & EFI_MEMORY_RUNTIME ? "RUN" : "", | |
595 | attr & EFI_MEMORY_XP ? "XP" : "", | |
596 | attr & EFI_MEMORY_RP ? "RP" : "", | |
597 | attr & EFI_MEMORY_WP ? "WP" : "", | |
598 | attr & EFI_MEMORY_UCE ? "UCE" : "", | |
599 | attr & EFI_MEMORY_WB ? "WB" : "", | |
600 | attr & EFI_MEMORY_WT ? "WT" : "", | |
601 | attr & EFI_MEMORY_WC ? "WC" : "", | |
602 | attr & EFI_MEMORY_UC ? "UC" : ""); | |
603 | return buf; | |
604 | } |