blob: 9035c1b74d5839471445facd9100b8522c2e9dd8 [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,
Leif Lindholm272686b2013-09-05 11:34:54 +010042};
43EXPORT_SYMBOL(efi);
Tom Gundersena9499fa2013-02-08 15:37:06 +000044
Dave Youngb2e0a542014-08-14 17:15:26 +080045static bool disable_runtime;
46static int __init setup_noefi(char *arg)
47{
48 disable_runtime = true;
49 return 0;
50}
51early_param("noefi", setup_noefi);
52
53bool efi_runtime_disabled(void)
54{
55 return disable_runtime;
56}
57
Dave Young5ae36832014-08-14 17:15:28 +080058static int __init parse_efi_cmdline(char *str)
59{
60 if (parse_option_str(str, "noruntime"))
61 disable_runtime = true;
62
63 return 0;
64}
65early_param("efi", parse_efi_cmdline);
66
Tom Gundersena9499fa2013-02-08 15:37:06 +000067static struct kobject *efi_kobj;
68static struct kobject *efivars_kobj;
69
70/*
71 * Let's not leave out systab information that snuck into
72 * the efivars driver
73 */
74static ssize_t systab_show(struct kobject *kobj,
75 struct kobj_attribute *attr, char *buf)
76{
77 char *str = buf;
78
79 if (!kobj || !buf)
80 return -EINVAL;
81
82 if (efi.mps != EFI_INVALID_TABLE_ADDR)
83 str += sprintf(str, "MPS=0x%lx\n", efi.mps);
84 if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
85 str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
86 if (efi.acpi != EFI_INVALID_TABLE_ADDR)
87 str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
88 if (efi.smbios != EFI_INVALID_TABLE_ADDR)
89 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +020090 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
91 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
Tom Gundersena9499fa2013-02-08 15:37:06 +000092 if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
93 str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
94 if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
95 str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
96 if (efi.uga != EFI_INVALID_TABLE_ADDR)
97 str += sprintf(str, "UGA=0x%lx\n", efi.uga);
98
99 return str - buf;
100}
101
102static struct kobj_attribute efi_attr_systab =
103 __ATTR(systab, 0400, systab_show, NULL);
104
Dave Younga0998eb2013-12-20 18:02:17 +0800105#define EFI_FIELD(var) efi.var
106
107#define EFI_ATTR_SHOW(name) \
108static ssize_t name##_show(struct kobject *kobj, \
109 struct kobj_attribute *attr, char *buf) \
110{ \
111 return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
112}
113
114EFI_ATTR_SHOW(fw_vendor);
115EFI_ATTR_SHOW(runtime);
116EFI_ATTR_SHOW(config_table);
117
118static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
119static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
120static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
121
Tom Gundersena9499fa2013-02-08 15:37:06 +0000122static struct attribute *efi_subsys_attrs[] = {
123 &efi_attr_systab.attr,
Dave Younga0998eb2013-12-20 18:02:17 +0800124 &efi_attr_fw_vendor.attr,
125 &efi_attr_runtime.attr,
126 &efi_attr_config_table.attr,
127 NULL,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000128};
129
Dave Younga0998eb2013-12-20 18:02:17 +0800130static umode_t efi_attr_is_visible(struct kobject *kobj,
131 struct attribute *attr, int n)
132{
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200133 if (attr == &efi_attr_fw_vendor.attr) {
134 if (efi_enabled(EFI_PARAVIRT) ||
135 efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
136 return 0;
137 } else if (attr == &efi_attr_runtime.attr) {
138 if (efi.runtime == EFI_INVALID_TABLE_ADDR)
139 return 0;
140 } else if (attr == &efi_attr_config_table.attr) {
141 if (efi.config_table == EFI_INVALID_TABLE_ADDR)
142 return 0;
143 }
Dave Younga0998eb2013-12-20 18:02:17 +0800144
Daniel Kiper9f27bc52014-06-30 19:52:58 +0200145 return attr->mode;
Dave Younga0998eb2013-12-20 18:02:17 +0800146}
147
Tom Gundersena9499fa2013-02-08 15:37:06 +0000148static struct attribute_group efi_subsys_attr_group = {
149 .attrs = efi_subsys_attrs,
Dave Younga0998eb2013-12-20 18:02:17 +0800150 .is_visible = efi_attr_is_visible,
Tom Gundersena9499fa2013-02-08 15:37:06 +0000151};
152
153static struct efivars generic_efivars;
154static struct efivar_operations generic_ops;
155
156static int generic_ops_register(void)
157{
158 generic_ops.get_variable = efi.get_variable;
159 generic_ops.set_variable = efi.set_variable;
160 generic_ops.get_next_variable = efi.get_next_variable;
Matt Fleminga614e192013-04-30 11:30:24 +0100161 generic_ops.query_variable_store = efi_query_variable_store;
Tom Gundersena9499fa2013-02-08 15:37:06 +0000162
163 return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
164}
165
166static void generic_ops_unregister(void)
167{
168 efivars_unregister(&generic_efivars);
169}
170
171/*
172 * We register the efi subsystem with the firmware subsystem and the
173 * efivars subsystem with the efi subsystem, if the system was booted with
174 * EFI.
175 */
176static int __init efisubsys_init(void)
177{
178 int error;
179
180 if (!efi_enabled(EFI_BOOT))
181 return 0;
182
183 /* We register the efi directory at /sys/firmware/efi */
184 efi_kobj = kobject_create_and_add("efi", firmware_kobj);
185 if (!efi_kobj) {
186 pr_err("efi: Firmware registration failed.\n");
187 return -ENOMEM;
188 }
189
190 error = generic_ops_register();
191 if (error)
192 goto err_put;
193
194 error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
195 if (error) {
196 pr_err("efi: Sysfs attribute export failed with error %d.\n",
197 error);
198 goto err_unregister;
199 }
200
Dave Young926172d2013-12-20 18:02:18 +0800201 error = efi_runtime_map_init(efi_kobj);
202 if (error)
203 goto err_remove_group;
204
Tom Gundersena9499fa2013-02-08 15:37:06 +0000205 /* and the standard mountpoint for efivarfs */
206 efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
207 if (!efivars_kobj) {
208 pr_err("efivars: Subsystem registration failed.\n");
209 error = -ENOMEM;
210 goto err_remove_group;
211 }
212
213 return 0;
214
215err_remove_group:
216 sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
217err_unregister:
218 generic_ops_unregister();
219err_put:
220 kobject_put(efi_kobj);
221 return error;
222}
223
224subsys_initcall(efisubsys_init);
Leif Lindholm272686b2013-09-05 11:34:54 +0100225
226
Leif Lindholm258f6fd2013-09-05 11:34:55 +0100227/*
228 * We can't ioremap data in EFI boot services RAM, because we've already mapped
229 * it as RAM. So, look it up in the existing EFI memory map instead. Only
230 * callable after efi_enter_virtual_mode and before efi_free_boot_services.
231 */
232void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
233{
234 struct efi_memory_map *map;
235 void *p;
236 map = efi.memmap;
237 if (!map)
238 return NULL;
239 if (WARN_ON(!map->map))
240 return NULL;
241 for (p = map->map; p < map->map_end; p += map->desc_size) {
242 efi_memory_desc_t *md = p;
243 u64 size = md->num_pages << EFI_PAGE_SHIFT;
244 u64 end = md->phys_addr + size;
245 if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
246 md->type != EFI_BOOT_SERVICES_CODE &&
247 md->type != EFI_BOOT_SERVICES_DATA)
248 continue;
249 if (!md->virt_addr)
250 continue;
251 if (phys_addr >= md->phys_addr && phys_addr < end) {
252 phys_addr += md->virt_addr - md->phys_addr;
253 return (__force void __iomem *)(unsigned long)phys_addr;
254 }
255 }
256 return NULL;
257}
258
Leif Lindholm272686b2013-09-05 11:34:54 +0100259static __initdata efi_config_table_type_t common_tables[] = {
260 {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
261 {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
262 {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
263 {MPS_TABLE_GUID, "MPS", &efi.mps},
264 {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
265 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
Ard Biesheuvele1ccbbc2014-10-14 16:34:47 +0200266 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
Leif Lindholm272686b2013-09-05 11:34:54 +0100267 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
Daeseok Youn69e60842014-02-13 17:16:36 +0900268 {NULL_GUID, NULL, NULL},
Leif Lindholm272686b2013-09-05 11:34:54 +0100269};
270
271static __init int match_config_table(efi_guid_t *guid,
272 unsigned long table,
273 efi_config_table_type_t *table_types)
274{
275 u8 str[EFI_VARIABLE_GUID_LEN + 1];
276 int i;
277
278 if (table_types) {
279 efi_guid_unparse(guid, str);
280
281 for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
282 efi_guid_unparse(&table_types[i].guid, str);
283
284 if (!efi_guidcmp(*guid, table_types[i].guid)) {
285 *(table_types[i].ptr) = table;
286 pr_cont(" %s=0x%lx ",
287 table_types[i].name, table);
288 return 1;
289 }
290 }
291 }
292
293 return 0;
294}
295
296int __init efi_config_init(efi_config_table_type_t *arch_tables)
297{
298 void *config_tables, *tablep;
299 int i, sz;
300
301 if (efi_enabled(EFI_64BIT))
302 sz = sizeof(efi_config_table_64_t);
303 else
304 sz = sizeof(efi_config_table_32_t);
305
306 /*
307 * Let's see what config tables the firmware passed to us.
308 */
309 config_tables = early_memremap(efi.systab->tables,
310 efi.systab->nr_tables * sz);
311 if (config_tables == NULL) {
312 pr_err("Could not map Configuration table!\n");
313 return -ENOMEM;
314 }
315
316 tablep = config_tables;
317 pr_info("");
318 for (i = 0; i < efi.systab->nr_tables; i++) {
319 efi_guid_t guid;
320 unsigned long table;
321
322 if (efi_enabled(EFI_64BIT)) {
323 u64 table64;
324 guid = ((efi_config_table_64_t *)tablep)->guid;
325 table64 = ((efi_config_table_64_t *)tablep)->table;
326 table = table64;
327#ifndef CONFIG_64BIT
328 if (table64 >> 32) {
329 pr_cont("\n");
330 pr_err("Table located above 4GB, disabling EFI.\n");
Daniel Kiperabc93f82014-06-30 19:52:56 +0200331 early_memunmap(config_tables,
Leif Lindholm272686b2013-09-05 11:34:54 +0100332 efi.systab->nr_tables * sz);
333 return -EINVAL;
334 }
335#endif
336 } else {
337 guid = ((efi_config_table_32_t *)tablep)->guid;
338 table = ((efi_config_table_32_t *)tablep)->table;
339 }
340
341 if (!match_config_table(&guid, table, common_tables))
342 match_config_table(&guid, table, arch_tables);
343
344 tablep += sz;
345 }
346 pr_cont("\n");
Daniel Kiperabc93f82014-06-30 19:52:56 +0200347 early_memunmap(config_tables, efi.systab->nr_tables * sz);
Matt Fleming0f8093a2014-01-15 13:36:33 +0000348
349 set_bit(EFI_CONFIG_TABLES, &efi.flags);
350
Leif Lindholm272686b2013-09-05 11:34:54 +0100351 return 0;
352}
Mark Salter0302f712013-12-30 12:12:12 -0500353
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800354#ifdef CONFIG_EFI_VARS_MODULE
355static int __init efi_load_efivars(void)
356{
357 struct platform_device *pdev;
358
359 if (!efi_enabled(EFI_RUNTIME_SERVICES))
360 return 0;
361
362 pdev = platform_device_register_simple("efivars", 0, NULL, 0);
363 return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
364}
365device_initcall(efi_load_efivars);
366#endif
367
Mark Salter0302f712013-12-30 12:12:12 -0500368#ifdef CONFIG_EFI_PARAMS_FROM_FDT
369
370#define UEFI_PARAM(name, prop, field) \
371 { \
372 { name }, \
373 { prop }, \
374 offsetof(struct efi_fdt_params, field), \
375 FIELD_SIZEOF(struct efi_fdt_params, field) \
376 }
377
378static __initdata struct {
379 const char name[32];
380 const char propname[32];
381 int offset;
382 int size;
383} dt_params[] = {
384 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
385 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
386 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
387 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
388 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
389};
390
391struct param_info {
392 int verbose;
Catalin Marinas29e24352014-07-08 16:54:18 +0100393 int found;
Mark Salter0302f712013-12-30 12:12:12 -0500394 void *params;
395};
396
397static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
398 int depth, void *data)
399{
400 struct param_info *info = data;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100401 const void *prop;
402 void *dest;
Mark Salter0302f712013-12-30 12:12:12 -0500403 u64 val;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100404 int i, len;
Mark Salter0302f712013-12-30 12:12:12 -0500405
406 if (depth != 1 ||
407 (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
408 return 0;
409
Mark Salter0302f712013-12-30 12:12:12 -0500410 for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
411 prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
Catalin Marinas29e24352014-07-08 16:54:18 +0100412 if (!prop)
Mark Salter0302f712013-12-30 12:12:12 -0500413 return 0;
Mark Salter0302f712013-12-30 12:12:12 -0500414 dest = info->params + dt_params[i].offset;
Catalin Marinas29e24352014-07-08 16:54:18 +0100415 info->found++;
Mark Salter0302f712013-12-30 12:12:12 -0500416
417 val = of_read_number(prop, len / sizeof(u32));
418
419 if (dt_params[i].size == sizeof(u32))
420 *(u32 *)dest = val;
421 else
422 *(u64 *)dest = val;
423
424 if (info->verbose)
425 pr_info(" %s: 0x%0*llx\n", dt_params[i].name,
426 dt_params[i].size * 2, val);
427 }
428 return 1;
429}
430
431int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
432{
433 struct param_info info;
Catalin Marinas29e24352014-07-08 16:54:18 +0100434 int ret;
435
436 pr_info("Getting EFI parameters from FDT:\n");
Mark Salter0302f712013-12-30 12:12:12 -0500437
438 info.verbose = verbose;
Catalin Marinas29e24352014-07-08 16:54:18 +0100439 info.found = 0;
Mark Salter0302f712013-12-30 12:12:12 -0500440 info.params = params;
441
Catalin Marinas29e24352014-07-08 16:54:18 +0100442 ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
443 if (!info.found)
444 pr_info("UEFI not found.\n");
445 else if (!ret)
446 pr_err("Can't find '%s' in device tree!\n",
447 dt_params[info.found].name);
448
449 return ret;
Mark Salter0302f712013-12-30 12:12:12 -0500450}
451#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200452
453static __initdata char memory_type_name[][20] = {
454 "Reserved",
455 "Loader Code",
456 "Loader Data",
457 "Boot Code",
458 "Boot Data",
459 "Runtime Code",
460 "Runtime Data",
461 "Conventional Memory",
462 "Unusable Memory",
463 "ACPI Reclaim Memory",
464 "ACPI Memory NVS",
465 "Memory Mapped I/O",
466 "MMIO Port Space",
467 "PAL Code"
468};
469
470char * __init efi_md_typeattr_format(char *buf, size_t size,
471 const efi_memory_desc_t *md)
472{
473 char *pos;
474 int type_len;
475 u64 attr;
476
477 pos = buf;
478 if (md->type >= ARRAY_SIZE(memory_type_name))
479 type_len = snprintf(pos, size, "[type=%u", md->type);
480 else
481 type_len = snprintf(pos, size, "[%-*s",
482 (int)(sizeof(memory_type_name[0]) - 1),
483 memory_type_name[md->type]);
484 if (type_len >= size)
485 return buf;
486
487 pos += type_len;
488 size -= type_len;
489
490 attr = md->attribute;
491 if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
492 EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP |
493 EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME))
494 snprintf(pos, size, "|attr=0x%016llx]",
495 (unsigned long long)attr);
496 else
497 snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
498 attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
499 attr & EFI_MEMORY_XP ? "XP" : "",
500 attr & EFI_MEMORY_RP ? "RP" : "",
501 attr & EFI_MEMORY_WP ? "WP" : "",
502 attr & EFI_MEMORY_UCE ? "UCE" : "",
503 attr & EFI_MEMORY_WB ? "WB" : "",
504 attr & EFI_MEMORY_WT ? "WT" : "",
505 attr & EFI_MEMORY_WC ? "WC" : "",
506 attr & EFI_MEMORY_UC ? "UC" : "");
507 return buf;
508}