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