blob: 48b4c356740f15f76b10a3f8286b8edcfe11e579 [file] [log] [blame]
Tom Gundersena9499fa2013-02-08 15:37:06 +00001/*
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
Leif Lindholm272686b2013-09-05 11:34:54 +010016#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
Tom Gundersena9499fa2013-02-08 15:37:06 +000018#include <linux/kobject.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/device.h>
22#include <linux/efi.h>
Mark Salter0302f712013-12-30 12:12:12 -050023#include <linux/of.h>
24#include <linux/of_fdt.h>
Leif Lindholm272686b2013-09-05 11:34:54 +010025#include <linux/io.h>
Lee, Chun-Yi28d54022014-07-09 18:39:29 +080026#include <linux/platform_device.h>
Leif Lindholm272686b2013-09-05 11:34:54 +010027
28struct 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,
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +020033 .smbios3 = EFI_INVALID_TABLE_ADDR,
Leif Lindholm272686b2013-09-05 11:34:54 +010034 .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,
Dave Younga0998eb2013-12-20 18:02:17 +080039 .fw_vendor = EFI_INVALID_TABLE_ADDR,
40 .runtime = EFI_INVALID_TABLE_ADDR,
41 .config_table = EFI_INVALID_TABLE_ADDR,
Peter Jones0bb54902015-04-28 18:44:31 -040042 .esrt = EFI_INVALID_TABLE_ADDR,
Leif Lindholm272686b2013-09-05 11:34:54 +010043};
44EXPORT_SYMBOL(efi);
Tom Gundersena9499fa2013-02-08 15:37:06 +000045
Dave Youngb2e0a542014-08-14 17:15:26 +080046static bool disable_runtime;
47static int __init setup_noefi(char *arg)
48{
49 disable_runtime = true;
50 return 0;
51}
52early_param("noefi", setup_noefi);
53
54bool efi_runtime_disabled(void)
55{
56 return disable_runtime;
57}
58
Dave Young5ae36832014-08-14 17:15:28 +080059static int __init parse_efi_cmdline(char *str)
60{
61 if (parse_option_str(str, "noruntime"))
62 disable_runtime = true;
63
64 return 0;
65}
66early_param("efi", parse_efi_cmdline);
67
Peter Jones0bb54902015-04-28 18:44:31 -040068struct kobject *efi_kobj;
Tom Gundersena9499fa2013-02-08 15:37:06 +000069static struct kobject *efivars_kobj;
70
71/*
72 * Let's not leave out systab information that snuck into
73 * the efivars driver
74 */
75static 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);
89 if (efi.smbios != EFI_INVALID_TABLE_ADDR)
90 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +020091 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
92 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
Tom Gundersena9499fa2013-02-08 15:37:06 +000093 if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
94 str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
95 if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
96 str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
97 if (efi.uga != EFI_INVALID_TABLE_ADDR)
98 str += sprintf(str, "UGA=0x%lx\n", efi.uga);
99
100 return str - buf;
101}
102
103static struct kobj_attribute efi_attr_systab =
104 __ATTR(systab, 0400, systab_show, NULL);
105
Dave Younga0998eb2013-12-20 18:02:17 +0800106#define EFI_FIELD(var) efi.var
107
108#define EFI_ATTR_SHOW(name) \
109static ssize_t name##_show(struct kobject *kobj, \
110 struct kobj_attribute *attr, char *buf) \
111{ \
112 return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
113}
114
115EFI_ATTR_SHOW(fw_vendor);
116EFI_ATTR_SHOW(runtime);
117EFI_ATTR_SHOW(config_table);
118
Steve McIntyre2859dff2015-01-09 15:29:53 +0000119static ssize_t fw_platform_size_show(struct kobject *kobj,
120 struct kobj_attribute *attr, char *buf)
121{
122 return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
123}
124
Dave Younga0998eb2013-12-20 18:02:17 +0800125static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
126static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
127static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
Steve McIntyre2859dff2015-01-09 15:29:53 +0000128static struct kobj_attribute efi_attr_fw_platform_size =
129 __ATTR_RO(fw_platform_size);
Dave Younga0998eb2013-12-20 18:02:17 +0800130
Tom Gundersena9499fa2013-02-08 15:37:06 +0000131static struct attribute *efi_subsys_attrs[] = {
132 &efi_attr_systab.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800133 &efi_attr_fw_vendor.attr,
134 &efi_attr_runtime.attr,
135 &efi_attr_config_table.attr,
Steve McIntyre2859dff2015-01-09 15:29:53 +0000136 &efi_attr_fw_platform_size.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800137 NULL,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000138};
139
Dave Younga0998eb2013-12-20 18:02:17 +0800140static umode_t efi_attr_is_visible(struct kobject *kobj,
141 struct attribute *attr, int n)
142{
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200143 if (attr == &efi_attr_fw_vendor.attr) {
144 if (efi_enabled(EFI_PARAVIRT) ||
145 efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
146 return 0;
147 } else if (attr == &efi_attr_runtime.attr) {
148 if (efi.runtime == EFI_INVALID_TABLE_ADDR)
149 return 0;
150 } else if (attr == &efi_attr_config_table.attr) {
151 if (efi.config_table == EFI_INVALID_TABLE_ADDR)
152 return 0;
153 }
Dave Younga0998eb2013-12-20 18:02:17 +0800154
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200155 return attr->mode;
Dave Younga0998eb2013-12-20 18:02:17 +0800156}
157
Tom Gundersena9499fa2013-02-08 15:37:06 +0000158static struct attribute_group efi_subsys_attr_group = {
159 .attrs = efi_subsys_attrs,
Dave Younga0998eb2013-12-20 18:02:17 +0800160 .is_visible = efi_attr_is_visible,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000161};
162
163static struct efivars generic_efivars;
164static struct efivar_operations generic_ops;
165
166static int generic_ops_register(void)
167{
168 generic_ops.get_variable = efi.get_variable;
169 generic_ops.set_variable = efi.set_variable;
170 generic_ops.get_next_variable = efi.get_next_variable;
Matt Fleminga614e192013-04-30 11:30:24 +0100171 generic_ops.query_variable_store = efi_query_variable_store;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000172
173 return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
174}
175
176static void generic_ops_unregister(void)
177{
178 efivars_unregister(&generic_efivars);
179}
180
181/*
182 * We register the efi subsystem with the firmware subsystem and the
183 * efivars subsystem with the efi subsystem, if the system was booted with
184 * EFI.
185 */
186static int __init efisubsys_init(void)
187{
188 int error;
189
190 if (!efi_enabled(EFI_BOOT))
191 return 0;
192
193 /* We register the efi directory at /sys/firmware/efi */
194 efi_kobj = kobject_create_and_add("efi", firmware_kobj);
195 if (!efi_kobj) {
196 pr_err("efi: Firmware registration failed.\n");
197 return -ENOMEM;
198 }
199
200 error = generic_ops_register();
201 if (error)
202 goto err_put;
203
204 error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
205 if (error) {
206 pr_err("efi: Sysfs attribute export failed with error %d.\n",
207 error);
208 goto err_unregister;
209 }
210
Dave Young926172d2013-12-20 18:02:18 +0800211 error = efi_runtime_map_init(efi_kobj);
212 if (error)
213 goto err_remove_group;
214
Tom Gundersena9499fa2013-02-08 15:37:06 +0000215 /* and the standard mountpoint for efivarfs */
216 efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
217 if (!efivars_kobj) {
218 pr_err("efivars: Subsystem registration failed.\n");
219 error = -ENOMEM;
220 goto err_remove_group;
221 }
222
223 return 0;
224
225err_remove_group:
226 sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
227err_unregister:
228 generic_ops_unregister();
229err_put:
230 kobject_put(efi_kobj);
231 return error;
232}
233
234subsys_initcall(efisubsys_init);
Leif Lindholm272686b2013-09-05 11:34:54 +0100235
Peter Jones0bb54902015-04-28 18:44:31 -0400236/*
237 * Find the efi memory descriptor for a given physical address. Given a
238 * physicall address, determine if it exists within an EFI Memory Map entry,
239 * and if so, populate the supplied memory descriptor with the appropriate
240 * data.
241 */
242int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
243{
244 struct efi_memory_map *map = efi.memmap;
245 void *p, *e;
246
247 if (!efi_enabled(EFI_MEMMAP)) {
248 pr_err_once("EFI_MEMMAP is not enabled.\n");
249 return -EINVAL;
250 }
251
252 if (!map) {
253 pr_err_once("efi.memmap is not set.\n");
254 return -EINVAL;
255 }
256 if (!out_md) {
257 pr_err_once("out_md is null.\n");
258 return -EINVAL;
259 }
260 if (WARN_ON_ONCE(!map->phys_map))
261 return -EINVAL;
262 if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0))
263 return -EINVAL;
264
265 e = map->phys_map + map->nr_map * map->desc_size;
266 for (p = map->phys_map; p < e; p += map->desc_size) {
267 efi_memory_desc_t *md;
268 u64 size;
269 u64 end;
270
271 /*
272 * If a driver calls this after efi_free_boot_services,
273 * ->map will be NULL, and the target may also not be mapped.
274 * So just always get our own virtual map on the CPU.
275 *
276 */
277 md = early_memremap((phys_addr_t)p, sizeof (*md));
278 if (!md) {
279 pr_err_once("early_memremap(%p, %zu) failed.\n",
280 p, sizeof (*md));
281 return -ENOMEM;
282 }
283
284 if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
285 md->type != EFI_BOOT_SERVICES_DATA &&
286 md->type != EFI_RUNTIME_SERVICES_DATA) {
287 early_memunmap(md, sizeof (*md));
288 continue;
289 }
290
291 size = md->num_pages << EFI_PAGE_SHIFT;
292 end = md->phys_addr + size;
293 if (phys_addr >= md->phys_addr && phys_addr < end) {
294 memcpy(out_md, md, sizeof(*out_md));
295 early_memunmap(md, sizeof (*md));
296 return 0;
297 }
298
299 early_memunmap(md, sizeof (*md));
300 }
301 pr_err_once("requested map not found.\n");
302 return -ENOENT;
303}
304
305/*
306 * Calculate the highest address of an efi memory descriptor.
307 */
308u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
309{
310 u64 size = md->num_pages << EFI_PAGE_SHIFT;
311 u64 end = md->phys_addr + size;
312 return end;
313}
Leif Lindholm272686b2013-09-05 11:34:54 +0100314
Leif Lindholm258f6fd2013-09-05 11:34:55 +0100315/*
316 * We can't ioremap data in EFI boot services RAM, because we've already mapped
317 * it as RAM. So, look it up in the existing EFI memory map instead. Only
318 * callable after efi_enter_virtual_mode and before efi_free_boot_services.
319 */
320void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
321{
322 struct efi_memory_map *map;
323 void *p;
324 map = efi.memmap;
325 if (!map)
326 return NULL;
327 if (WARN_ON(!map->map))
328 return NULL;
329 for (p = map->map; p < map->map_end; p += map->desc_size) {
330 efi_memory_desc_t *md = p;
331 u64 size = md->num_pages << EFI_PAGE_SHIFT;
332 u64 end = md->phys_addr + size;
333 if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
334 md->type != EFI_BOOT_SERVICES_CODE &&
335 md->type != EFI_BOOT_SERVICES_DATA)
336 continue;
337 if (!md->virt_addr)
338 continue;
339 if (phys_addr >= md->phys_addr && phys_addr < end) {
340 phys_addr += md->virt_addr - md->phys_addr;
341 return (__force void __iomem *)(unsigned long)phys_addr;
342 }
343 }
344 return NULL;
345}
346
Leif Lindholm272686b2013-09-05 11:34:54 +0100347static __initdata efi_config_table_type_t common_tables[] = {
348 {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
349 {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
350 {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
351 {MPS_TABLE_GUID, "MPS", &efi.mps},
352 {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
353 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200354 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
Leif Lindholm272686b2013-09-05 11:34:54 +0100355 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
Peter Jones0bb54902015-04-28 18:44:31 -0400356 {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
Daeseok Youn69e60842014-02-13 17:16:36 +0900357 {NULL_GUID, NULL, NULL},
Leif Lindholm272686b2013-09-05 11:34:54 +0100358};
359
360static __init int match_config_table(efi_guid_t *guid,
361 unsigned long table,
362 efi_config_table_type_t *table_types)
363{
Leif Lindholm272686b2013-09-05 11:34:54 +0100364 int i;
365
366 if (table_types) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100367 for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
Leif Lindholm272686b2013-09-05 11:34:54 +0100368 if (!efi_guidcmp(*guid, table_types[i].guid)) {
369 *(table_types[i].ptr) = table;
370 pr_cont(" %s=0x%lx ",
371 table_types[i].name, table);
372 return 1;
373 }
374 }
375 }
376
377 return 0;
378}
379
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200380int __init efi_config_parse_tables(void *config_tables, int count, int sz,
381 efi_config_table_type_t *arch_tables)
382{
383 void *tablep;
384 int i;
385
386 tablep = config_tables;
387 pr_info("");
388 for (i = 0; i < count; i++) {
389 efi_guid_t guid;
390 unsigned long table;
391
392 if (efi_enabled(EFI_64BIT)) {
393 u64 table64;
394 guid = ((efi_config_table_64_t *)tablep)->guid;
395 table64 = ((efi_config_table_64_t *)tablep)->table;
396 table = table64;
397#ifndef CONFIG_64BIT
398 if (table64 >> 32) {
399 pr_cont("\n");
400 pr_err("Table located above 4GB, disabling EFI.\n");
401 return -EINVAL;
402 }
403#endif
404 } else {
405 guid = ((efi_config_table_32_t *)tablep)->guid;
406 table = ((efi_config_table_32_t *)tablep)->table;
407 }
408
409 if (!match_config_table(&guid, table, common_tables))
410 match_config_table(&guid, table, arch_tables);
411
412 tablep += sz;
413 }
414 pr_cont("\n");
415 set_bit(EFI_CONFIG_TABLES, &efi.flags);
416 return 0;
417}
418
Leif Lindholm272686b2013-09-05 11:34:54 +0100419int __init efi_config_init(efi_config_table_type_t *arch_tables)
420{
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200421 void *config_tables;
422 int sz, ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100423
424 if (efi_enabled(EFI_64BIT))
425 sz = sizeof(efi_config_table_64_t);
426 else
427 sz = sizeof(efi_config_table_32_t);
428
429 /*
430 * Let's see what config tables the firmware passed to us.
431 */
432 config_tables = early_memremap(efi.systab->tables,
433 efi.systab->nr_tables * sz);
434 if (config_tables == NULL) {
435 pr_err("Could not map Configuration table!\n");
436 return -ENOMEM;
437 }
438
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200439 ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
440 arch_tables);
Leif Lindholm272686b2013-09-05 11:34:54 +0100441
Daniel Kiperabc93f82014-06-30 19:52:56 +0200442 early_memunmap(config_tables, efi.systab->nr_tables * sz);
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200443 return ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100444}
Mark Salter0302f712013-12-30 12:12:12 -0500445
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800446#ifdef CONFIG_EFI_VARS_MODULE
447static int __init efi_load_efivars(void)
448{
449 struct platform_device *pdev;
450
451 if (!efi_enabled(EFI_RUNTIME_SERVICES))
452 return 0;
453
454 pdev = platform_device_register_simple("efivars", 0, NULL, 0);
455 return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
456}
457device_initcall(efi_load_efivars);
458#endif
459
Mark Salter0302f712013-12-30 12:12:12 -0500460#ifdef CONFIG_EFI_PARAMS_FROM_FDT
461
462#define UEFI_PARAM(name, prop, field) \
463 { \
464 { name }, \
465 { prop }, \
466 offsetof(struct efi_fdt_params, field), \
467 FIELD_SIZEOF(struct efi_fdt_params, field) \
468 }
469
470static __initdata struct {
471 const char name[32];
472 const char propname[32];
473 int offset;
474 int size;
475} dt_params[] = {
476 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
477 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
478 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
479 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
480 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
481};
482
483struct param_info {
484 int verbose;
Catalin Marinas29e24352014-07-08 16:54:18 +0100485 int found;
Mark Salter0302f712013-12-30 12:12:12 -0500486 void *params;
487};
488
489static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
490 int depth, void *data)
491{
492 struct param_info *info = data;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100493 const void *prop;
494 void *dest;
Mark Salter0302f712013-12-30 12:12:12 -0500495 u64 val;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100496 int i, len;
Mark Salter0302f712013-12-30 12:12:12 -0500497
Leif Lindholm11629302015-01-20 16:34:38 +0000498 if (depth != 1 || strcmp(uname, "chosen") != 0)
Mark Salter0302f712013-12-30 12:12:12 -0500499 return 0;
500
Mark Salter0302f712013-12-30 12:12:12 -0500501 for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
502 prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
Catalin Marinas29e24352014-07-08 16:54:18 +0100503 if (!prop)
Mark Salter0302f712013-12-30 12:12:12 -0500504 return 0;
Mark Salter0302f712013-12-30 12:12:12 -0500505 dest = info->params + dt_params[i].offset;
Catalin Marinas29e24352014-07-08 16:54:18 +0100506 info->found++;
Mark Salter0302f712013-12-30 12:12:12 -0500507
508 val = of_read_number(prop, len / sizeof(u32));
509
510 if (dt_params[i].size == sizeof(u32))
511 *(u32 *)dest = val;
512 else
513 *(u64 *)dest = val;
514
515 if (info->verbose)
516 pr_info(" %s: 0x%0*llx\n", dt_params[i].name,
517 dt_params[i].size * 2, val);
518 }
519 return 1;
520}
521
522int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
523{
524 struct param_info info;
Catalin Marinas29e24352014-07-08 16:54:18 +0100525 int ret;
526
527 pr_info("Getting EFI parameters from FDT:\n");
Mark Salter0302f712013-12-30 12:12:12 -0500528
529 info.verbose = verbose;
Catalin Marinas29e24352014-07-08 16:54:18 +0100530 info.found = 0;
Mark Salter0302f712013-12-30 12:12:12 -0500531 info.params = params;
532
Catalin Marinas29e24352014-07-08 16:54:18 +0100533 ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
534 if (!info.found)
535 pr_info("UEFI not found.\n");
536 else if (!ret)
537 pr_err("Can't find '%s' in device tree!\n",
538 dt_params[info.found].name);
539
540 return ret;
Mark Salter0302f712013-12-30 12:12:12 -0500541}
542#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200543
544static __initdata char memory_type_name[][20] = {
545 "Reserved",
546 "Loader Code",
547 "Loader Data",
548 "Boot Code",
549 "Boot Data",
550 "Runtime Code",
551 "Runtime Data",
552 "Conventional Memory",
553 "Unusable Memory",
554 "ACPI Reclaim Memory",
555 "ACPI Memory NVS",
556 "Memory Mapped I/O",
557 "MMIO Port Space",
558 "PAL Code"
559};
560
561char * __init efi_md_typeattr_format(char *buf, size_t size,
562 const efi_memory_desc_t *md)
563{
564 char *pos;
565 int type_len;
566 u64 attr;
567
568 pos = buf;
569 if (md->type >= ARRAY_SIZE(memory_type_name))
570 type_len = snprintf(pos, size, "[type=%u", md->type);
571 else
572 type_len = snprintf(pos, size, "[%-*s",
573 (int)(sizeof(memory_type_name[0]) - 1),
574 memory_type_name[md->type]);
575 if (type_len >= size)
576 return buf;
577
578 pos += type_len;
579 size -= type_len;
580
581 attr = md->attribute;
582 if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
583 EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP |
584 EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME))
585 snprintf(pos, size, "|attr=0x%016llx]",
586 (unsigned long long)attr);
587 else
588 snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
589 attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
590 attr & EFI_MEMORY_XP ? "XP" : "",
591 attr & EFI_MEMORY_RP ? "RP" : "",
592 attr & EFI_MEMORY_WP ? "WP" : "",
593 attr & EFI_MEMORY_UCE ? "UCE" : "",
594 attr & EFI_MEMORY_WB ? "WB" : "",
595 attr & EFI_MEMORY_WT ? "WT" : "",
596 attr & EFI_MEMORY_WC ? "WC" : "",
597 attr & EFI_MEMORY_UC ? "UC" : "");
598 return buf;
599}