]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/firmware/efi/efi.c
Merge remote-tracking branch 'h8300/h8300-next'
[karo-tx-linux.git] / 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.get_next_variable = efi.get_next_variable;
184         generic_ops.query_variable_store = efi_query_variable_store;
185
186         return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
187 }
188
189 static void generic_ops_unregister(void)
190 {
191         efivars_unregister(&generic_efivars);
192 }
193
194 /*
195  * We register the efi subsystem with the firmware subsystem and the
196  * efivars subsystem with the efi subsystem, if the system was booted with
197  * EFI.
198  */
199 static int __init efisubsys_init(void)
200 {
201         int error;
202
203         if (!efi_enabled(EFI_BOOT))
204                 return 0;
205
206         /* We register the efi directory at /sys/firmware/efi */
207         efi_kobj = kobject_create_and_add("efi", firmware_kobj);
208         if (!efi_kobj) {
209                 pr_err("efi: Firmware registration failed.\n");
210                 return -ENOMEM;
211         }
212
213         error = generic_ops_register();
214         if (error)
215                 goto err_put;
216
217         error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
218         if (error) {
219                 pr_err("efi: Sysfs attribute export failed with error %d.\n",
220                        error);
221                 goto err_unregister;
222         }
223
224         error = efi_runtime_map_init(efi_kobj);
225         if (error)
226                 goto err_remove_group;
227
228         /* and the standard mountpoint for efivarfs */
229         error = sysfs_create_mount_point(efi_kobj, "efivars");
230         if (error) {
231                 pr_err("efivars: Subsystem registration failed.\n");
232                 goto err_remove_group;
233         }
234
235         return 0;
236
237 err_remove_group:
238         sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
239 err_unregister:
240         generic_ops_unregister();
241 err_put:
242         kobject_put(efi_kobj);
243         return error;
244 }
245
246 subsys_initcall(efisubsys_init);
247
248 /*
249  * Find the efi memory descriptor for a given physical address.  Given a
250  * physicall address, determine if it exists within an EFI Memory Map entry,
251  * and if so, populate the supplied memory descriptor with the appropriate
252  * data.
253  */
254 int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
255 {
256         struct efi_memory_map *map = efi.memmap;
257         phys_addr_t p, e;
258
259         if (!efi_enabled(EFI_MEMMAP)) {
260                 pr_err_once("EFI_MEMMAP is not enabled.\n");
261                 return -EINVAL;
262         }
263
264         if (!map) {
265                 pr_err_once("efi.memmap is not set.\n");
266                 return -EINVAL;
267         }
268         if (!out_md) {
269                 pr_err_once("out_md is null.\n");
270                 return -EINVAL;
271         }
272         if (WARN_ON_ONCE(!map->phys_map))
273                 return -EINVAL;
274         if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0))
275                 return -EINVAL;
276
277         e = map->phys_map + map->nr_map * map->desc_size;
278         for (p = map->phys_map; p < e; p += map->desc_size) {
279                 efi_memory_desc_t *md;
280                 u64 size;
281                 u64 end;
282
283                 /*
284                  * If a driver calls this after efi_free_boot_services,
285                  * ->map will be NULL, and the target may also not be mapped.
286                  * So just always get our own virtual map on the CPU.
287                  *
288                  */
289                 md = early_memremap(p, sizeof (*md));
290                 if (!md) {
291                         pr_err_once("early_memremap(%pa, %zu) failed.\n",
292                                     &p, sizeof (*md));
293                         return -ENOMEM;
294                 }
295
296                 if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
297                     md->type != EFI_BOOT_SERVICES_DATA &&
298                     md->type != EFI_RUNTIME_SERVICES_DATA) {
299                         early_memunmap(md, sizeof (*md));
300                         continue;
301                 }
302
303                 size = md->num_pages << EFI_PAGE_SHIFT;
304                 end = md->phys_addr + size;
305                 if (phys_addr >= md->phys_addr && phys_addr < end) {
306                         memcpy(out_md, md, sizeof(*out_md));
307                         early_memunmap(md, sizeof (*md));
308                         return 0;
309                 }
310
311                 early_memunmap(md, sizeof (*md));
312         }
313         pr_err_once("requested map not found.\n");
314         return -ENOENT;
315 }
316
317 /*
318  * Calculate the highest address of an efi memory descriptor.
319  */
320 u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
321 {
322         u64 size = md->num_pages << EFI_PAGE_SHIFT;
323         u64 end = md->phys_addr + size;
324         return end;
325 }
326
327 /*
328  * We can't ioremap data in EFI boot services RAM, because we've already mapped
329  * it as RAM.  So, look it up in the existing EFI memory map instead.  Only
330  * callable after efi_enter_virtual_mode and before efi_free_boot_services.
331  */
332 void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
333 {
334         struct efi_memory_map *map;
335         void *p;
336         map = efi.memmap;
337         if (!map)
338                 return NULL;
339         if (WARN_ON(!map->map))
340                 return NULL;
341         for (p = map->map; p < map->map_end; p += map->desc_size) {
342                 efi_memory_desc_t *md = p;
343                 u64 size = md->num_pages << EFI_PAGE_SHIFT;
344                 u64 end = md->phys_addr + size;
345                 if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
346                     md->type != EFI_BOOT_SERVICES_CODE &&
347                     md->type != EFI_BOOT_SERVICES_DATA)
348                         continue;
349                 if (!md->virt_addr)
350                         continue;
351                 if (phys_addr >= md->phys_addr && phys_addr < end) {
352                         phys_addr += md->virt_addr - md->phys_addr;
353                         return (__force void __iomem *)(unsigned long)phys_addr;
354                 }
355         }
356         return NULL;
357 }
358
359 static __initdata efi_config_table_type_t common_tables[] = {
360         {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
361         {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
362         {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
363         {MPS_TABLE_GUID, "MPS", &efi.mps},
364         {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
365         {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
366         {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
367         {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
368         {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
369         {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
370         {NULL_GUID, NULL, NULL},
371 };
372
373 static __init int match_config_table(efi_guid_t *guid,
374                                      unsigned long table,
375                                      efi_config_table_type_t *table_types)
376 {
377         int i;
378
379         if (table_types) {
380                 for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
381                         if (!efi_guidcmp(*guid, table_types[i].guid)) {
382                                 *(table_types[i].ptr) = table;
383                                 pr_cont(" %s=0x%lx ",
384                                         table_types[i].name, table);
385                                 return 1;
386                         }
387                 }
388         }
389
390         return 0;
391 }
392
393 int __init efi_config_parse_tables(void *config_tables, int count, int sz,
394                                    efi_config_table_type_t *arch_tables)
395 {
396         void *tablep;
397         int i;
398
399         tablep = config_tables;
400         pr_info("");
401         for (i = 0; i < count; i++) {
402                 efi_guid_t guid;
403                 unsigned long table;
404
405                 if (efi_enabled(EFI_64BIT)) {
406                         u64 table64;
407                         guid = ((efi_config_table_64_t *)tablep)->guid;
408                         table64 = ((efi_config_table_64_t *)tablep)->table;
409                         table = table64;
410 #ifndef CONFIG_64BIT
411                         if (table64 >> 32) {
412                                 pr_cont("\n");
413                                 pr_err("Table located above 4GB, disabling EFI.\n");
414                                 return -EINVAL;
415                         }
416 #endif
417                 } else {
418                         guid = ((efi_config_table_32_t *)tablep)->guid;
419                         table = ((efi_config_table_32_t *)tablep)->table;
420                 }
421
422                 if (!match_config_table(&guid, table, common_tables))
423                         match_config_table(&guid, table, arch_tables);
424
425                 tablep += sz;
426         }
427         pr_cont("\n");
428         set_bit(EFI_CONFIG_TABLES, &efi.flags);
429
430         /* Parse the EFI Properties table if it exists */
431         if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
432                 efi_properties_table_t *tbl;
433
434                 tbl = early_memremap(efi.properties_table, sizeof(*tbl));
435                 if (tbl == NULL) {
436                         pr_err("Could not map Properties table!\n");
437                         return -ENOMEM;
438                 }
439
440                 if (tbl->memory_protection_attribute &
441                     EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
442                         set_bit(EFI_NX_PE_DATA, &efi.flags);
443
444                 early_memunmap(tbl, sizeof(*tbl));
445         }
446
447         return 0;
448 }
449
450 int __init efi_config_init(efi_config_table_type_t *arch_tables)
451 {
452         void *config_tables;
453         int sz, ret;
454
455         if (efi_enabled(EFI_64BIT))
456                 sz = sizeof(efi_config_table_64_t);
457         else
458                 sz = sizeof(efi_config_table_32_t);
459
460         /*
461          * Let's see what config tables the firmware passed to us.
462          */
463         config_tables = early_memremap(efi.systab->tables,
464                                        efi.systab->nr_tables * sz);
465         if (config_tables == NULL) {
466                 pr_err("Could not map Configuration table!\n");
467                 return -ENOMEM;
468         }
469
470         ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
471                                       arch_tables);
472
473         early_memunmap(config_tables, efi.systab->nr_tables * sz);
474         return ret;
475 }
476
477 #ifdef CONFIG_EFI_VARS_MODULE
478 static int __init efi_load_efivars(void)
479 {
480         struct platform_device *pdev;
481
482         if (!efi_enabled(EFI_RUNTIME_SERVICES))
483                 return 0;
484
485         pdev = platform_device_register_simple("efivars", 0, NULL, 0);
486         return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
487 }
488 device_initcall(efi_load_efivars);
489 #endif
490
491 #ifdef CONFIG_EFI_PARAMS_FROM_FDT
492
493 #define UEFI_PARAM(name, prop, field)                      \
494         {                                                  \
495                 { name },                                  \
496                 { prop },                                  \
497                 offsetof(struct efi_fdt_params, field),    \
498                 FIELD_SIZEOF(struct efi_fdt_params, field) \
499         }
500
501 static __initdata struct {
502         const char name[32];
503         const char propname[32];
504         int offset;
505         int size;
506 } dt_params[] = {
507         UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
508         UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
509         UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
510         UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
511         UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
512 };
513
514 struct param_info {
515         int found;
516         void *params;
517 };
518
519 static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
520                                        int depth, void *data)
521 {
522         struct param_info *info = data;
523         const void *prop;
524         void *dest;
525         u64 val;
526         int i, len;
527
528         if (depth != 1 || strcmp(uname, "chosen") != 0)
529                 return 0;
530
531         for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
532                 prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
533                 if (!prop)
534                         return 0;
535                 dest = info->params + dt_params[i].offset;
536                 info->found++;
537
538                 val = of_read_number(prop, len / sizeof(u32));
539
540                 if (dt_params[i].size == sizeof(u32))
541                         *(u32 *)dest = val;
542                 else
543                         *(u64 *)dest = val;
544
545                 if (efi_enabled(EFI_DBG))
546                         pr_info("  %s: 0x%0*llx\n", dt_params[i].name,
547                                 dt_params[i].size * 2, val);
548         }
549         return 1;
550 }
551
552 int __init efi_get_fdt_params(struct efi_fdt_params *params)
553 {
554         struct param_info info;
555         int ret;
556
557         pr_info("Getting EFI parameters from FDT:\n");
558
559         info.found = 0;
560         info.params = params;
561
562         ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
563         if (!info.found)
564                 pr_info("UEFI not found.\n");
565         else if (!ret)
566                 pr_err("Can't find '%s' in device tree!\n",
567                        dt_params[info.found].name);
568
569         return ret;
570 }
571 #endif /* CONFIG_EFI_PARAMS_FROM_FDT */
572
573 static __initdata char memory_type_name[][20] = {
574         "Reserved",
575         "Loader Code",
576         "Loader Data",
577         "Boot Code",
578         "Boot Data",
579         "Runtime Code",
580         "Runtime Data",
581         "Conventional Memory",
582         "Unusable Memory",
583         "ACPI Reclaim Memory",
584         "ACPI Memory NVS",
585         "Memory Mapped I/O",
586         "MMIO Port Space",
587         "PAL Code"
588 };
589
590 char * __init efi_md_typeattr_format(char *buf, size_t size,
591                                      const efi_memory_desc_t *md)
592 {
593         char *pos;
594         int type_len;
595         u64 attr;
596
597         pos = buf;
598         if (md->type >= ARRAY_SIZE(memory_type_name))
599                 type_len = snprintf(pos, size, "[type=%u", md->type);
600         else
601                 type_len = snprintf(pos, size, "[%-*s",
602                                     (int)(sizeof(memory_type_name[0]) - 1),
603                                     memory_type_name[md->type]);
604         if (type_len >= size)
605                 return buf;
606
607         pos += type_len;
608         size -= type_len;
609
610         attr = md->attribute;
611         if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
612                      EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
613                      EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
614                      EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
615                 snprintf(pos, size, "|attr=0x%016llx]",
616                          (unsigned long long)attr);
617         else
618                 snprintf(pos, size, "|%3s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
619                          attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
620                          attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
621                          attr & EFI_MEMORY_XP      ? "XP"  : "",
622                          attr & EFI_MEMORY_RP      ? "RP"  : "",
623                          attr & EFI_MEMORY_WP      ? "WP"  : "",
624                          attr & EFI_MEMORY_RO      ? "RO"  : "",
625                          attr & EFI_MEMORY_UCE     ? "UCE" : "",
626                          attr & EFI_MEMORY_WB      ? "WB"  : "",
627                          attr & EFI_MEMORY_WT      ? "WT"  : "",
628                          attr & EFI_MEMORY_WC      ? "WC"  : "",
629                          attr & EFI_MEMORY_UC      ? "UC"  : "");
630         return buf;
631 }
632
633 /*
634  * efi_mem_attributes - lookup memmap attributes for physical address
635  * @phys_addr: the physical address to lookup
636  *
637  * Search in the EFI memory map for the region covering
638  * @phys_addr. Returns the EFI memory attributes if the region
639  * was found in the memory map, 0 otherwise.
640  *
641  * Despite being marked __weak, most architectures should *not*
642  * override this function. It is __weak solely for the benefit
643  * of ia64 which has a funky EFI memory map that doesn't work
644  * the same way as other architectures.
645  */
646 u64 __weak efi_mem_attributes(unsigned long phys_addr)
647 {
648         struct efi_memory_map *map;
649         efi_memory_desc_t *md;
650         void *p;
651
652         if (!efi_enabled(EFI_MEMMAP))
653                 return 0;
654
655         map = efi.memmap;
656         for (p = map->map; p < map->map_end; p += map->desc_size) {
657                 md = p;
658                 if ((md->phys_addr <= phys_addr) &&
659                     (phys_addr < (md->phys_addr +
660                     (md->num_pages << EFI_PAGE_SHIFT))))
661                         return md->attribute;
662         }
663         return 0;
664 }