blob: b7ba9d8ec4b0b58ea7dbc59ec9294a83cb2b6c35 [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
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200296int __init efi_config_parse_tables(void *config_tables, int count, int sz,
297 efi_config_table_type_t *arch_tables)
298{
299 void *tablep;
300 int i;
301
302 tablep = config_tables;
303 pr_info("");
304 for (i = 0; i < count; i++) {
305 efi_guid_t guid;
306 unsigned long table;
307
308 if (efi_enabled(EFI_64BIT)) {
309 u64 table64;
310 guid = ((efi_config_table_64_t *)tablep)->guid;
311 table64 = ((efi_config_table_64_t *)tablep)->table;
312 table = table64;
313#ifndef CONFIG_64BIT
314 if (table64 >> 32) {
315 pr_cont("\n");
316 pr_err("Table located above 4GB, disabling EFI.\n");
317 return -EINVAL;
318 }
319#endif
320 } else {
321 guid = ((efi_config_table_32_t *)tablep)->guid;
322 table = ((efi_config_table_32_t *)tablep)->table;
323 }
324
325 if (!match_config_table(&guid, table, common_tables))
326 match_config_table(&guid, table, arch_tables);
327
328 tablep += sz;
329 }
330 pr_cont("\n");
331 set_bit(EFI_CONFIG_TABLES, &efi.flags);
332 return 0;
333}
334
Leif Lindholm272686b2013-09-05 11:34:54 +0100335int __init efi_config_init(efi_config_table_type_t *arch_tables)
336{
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200337 void *config_tables;
338 int sz, ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100339
340 if (efi_enabled(EFI_64BIT))
341 sz = sizeof(efi_config_table_64_t);
342 else
343 sz = sizeof(efi_config_table_32_t);
344
345 /*
346 * Let's see what config tables the firmware passed to us.
347 */
348 config_tables = early_memremap(efi.systab->tables,
349 efi.systab->nr_tables * sz);
350 if (config_tables == NULL) {
351 pr_err("Could not map Configuration table!\n");
352 return -ENOMEM;
353 }
354
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200355 ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
356 arch_tables);
Leif Lindholm272686b2013-09-05 11:34:54 +0100357
Daniel Kiperabc93f82014-06-30 19:52:56 +0200358 early_memunmap(config_tables, efi.systab->nr_tables * sz);
Ard Biesheuvel7bb68412014-10-18 15:04:15 +0200359 return ret;
Leif Lindholm272686b2013-09-05 11:34:54 +0100360}
Mark Salter0302f712013-12-30 12:12:12 -0500361
Lee, Chun-Yi28d54022014-07-09 18:39:29 +0800362#ifdef CONFIG_EFI_VARS_MODULE
363static int __init efi_load_efivars(void)
364{
365 struct platform_device *pdev;
366
367 if (!efi_enabled(EFI_RUNTIME_SERVICES))
368 return 0;
369
370 pdev = platform_device_register_simple("efivars", 0, NULL, 0);
371 return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
372}
373device_initcall(efi_load_efivars);
374#endif
375
Mark Salter0302f712013-12-30 12:12:12 -0500376#ifdef CONFIG_EFI_PARAMS_FROM_FDT
377
378#define UEFI_PARAM(name, prop, field) \
379 { \
380 { name }, \
381 { prop }, \
382 offsetof(struct efi_fdt_params, field), \
383 FIELD_SIZEOF(struct efi_fdt_params, field) \
384 }
385
386static __initdata struct {
387 const char name[32];
388 const char propname[32];
389 int offset;
390 int size;
391} dt_params[] = {
392 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
393 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
394 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
395 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
396 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
397};
398
399struct param_info {
400 int verbose;
Catalin Marinas29e24352014-07-08 16:54:18 +0100401 int found;
Mark Salter0302f712013-12-30 12:12:12 -0500402 void *params;
403};
404
405static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
406 int depth, void *data)
407{
408 struct param_info *info = data;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100409 const void *prop;
410 void *dest;
Mark Salter0302f712013-12-30 12:12:12 -0500411 u64 val;
Catalin Marinas6fb8cc82014-06-02 11:31:06 +0100412 int i, len;
Mark Salter0302f712013-12-30 12:12:12 -0500413
414 if (depth != 1 ||
415 (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
416 return 0;
417
Mark Salter0302f712013-12-30 12:12:12 -0500418 for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
419 prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
Catalin Marinas29e24352014-07-08 16:54:18 +0100420 if (!prop)
Mark Salter0302f712013-12-30 12:12:12 -0500421 return 0;
Mark Salter0302f712013-12-30 12:12:12 -0500422 dest = info->params + dt_params[i].offset;
Catalin Marinas29e24352014-07-08 16:54:18 +0100423 info->found++;
Mark Salter0302f712013-12-30 12:12:12 -0500424
425 val = of_read_number(prop, len / sizeof(u32));
426
427 if (dt_params[i].size == sizeof(u32))
428 *(u32 *)dest = val;
429 else
430 *(u64 *)dest = val;
431
432 if (info->verbose)
433 pr_info(" %s: 0x%0*llx\n", dt_params[i].name,
434 dt_params[i].size * 2, val);
435 }
436 return 1;
437}
438
439int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
440{
441 struct param_info info;
Catalin Marinas29e24352014-07-08 16:54:18 +0100442 int ret;
443
444 pr_info("Getting EFI parameters from FDT:\n");
Mark Salter0302f712013-12-30 12:12:12 -0500445
446 info.verbose = verbose;
Catalin Marinas29e24352014-07-08 16:54:18 +0100447 info.found = 0;
Mark Salter0302f712013-12-30 12:12:12 -0500448 info.params = params;
449
Catalin Marinas29e24352014-07-08 16:54:18 +0100450 ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
451 if (!info.found)
452 pr_info("UEFI not found.\n");
453 else if (!ret)
454 pr_err("Can't find '%s' in device tree!\n",
455 dt_params[info.found].name);
456
457 return ret;
Mark Salter0302f712013-12-30 12:12:12 -0500458}
459#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
Laszlo Ersek98d2a6c2014-09-03 13:32:20 +0200460
461static __initdata char memory_type_name[][20] = {
462 "Reserved",
463 "Loader Code",
464 "Loader Data",
465 "Boot Code",
466 "Boot Data",
467 "Runtime Code",
468 "Runtime Data",
469 "Conventional Memory",
470 "Unusable Memory",
471 "ACPI Reclaim Memory",
472 "ACPI Memory NVS",
473 "Memory Mapped I/O",
474 "MMIO Port Space",
475 "PAL Code"
476};
477
478char * __init efi_md_typeattr_format(char *buf, size_t size,
479 const efi_memory_desc_t *md)
480{
481 char *pos;
482 int type_len;
483 u64 attr;
484
485 pos = buf;
486 if (md->type >= ARRAY_SIZE(memory_type_name))
487 type_len = snprintf(pos, size, "[type=%u", md->type);
488 else
489 type_len = snprintf(pos, size, "[%-*s",
490 (int)(sizeof(memory_type_name[0]) - 1),
491 memory_type_name[md->type]);
492 if (type_len >= size)
493 return buf;
494
495 pos += type_len;
496 size -= type_len;
497
498 attr = md->attribute;
499 if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
500 EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP |
501 EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME))
502 snprintf(pos, size, "|attr=0x%016llx]",
503 (unsigned long long)attr);
504 else
505 snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
506 attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
507 attr & EFI_MEMORY_XP ? "XP" : "",
508 attr & EFI_MEMORY_RP ? "RP" : "",
509 attr & EFI_MEMORY_WP ? "WP" : "",
510 attr & EFI_MEMORY_UCE ? "UCE" : "",
511 attr & EFI_MEMORY_WB ? "WB" : "",
512 attr & EFI_MEMORY_WT ? "WT" : "",
513 attr & EFI_MEMORY_WC ? "WC" : "",
514 attr & EFI_MEMORY_UC ? "UC" : "");
515 return buf;
516}