aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efi/Kconfig11
-rw-r--r--drivers/firmware/efi/Makefile1
-rw-r--r--drivers/firmware/efi/efi.c45
-rw-r--r--drivers/firmware/efi/runtime-map.c181
4 files changed, 237 insertions, 1 deletions
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 6aecbc86ec94..1e75f48b61f8 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -36,6 +36,17 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE
36 backend for pstore by default. This setting can be overridden 36 backend for pstore by default. This setting can be overridden
37 using the efivars module's pstore_disable parameter. 37 using the efivars module's pstore_disable parameter.
38 38
39config EFI_RUNTIME_MAP
40 bool "Export efi runtime maps to sysfs"
41 depends on X86 && EFI && KEXEC
42 default y
43 help
44 Export efi runtime memory maps to /sys/firmware/efi/runtime-map.
45 That memory map is used for example by kexec to set up efi virtual
46 mapping the 2nd kernel, but can also be used for debugging purposes.
47
48 See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
49
39endmenu 50endmenu
40 51
41config UEFI_CPER 52config UEFI_CPER
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index 6c2a41ec21ba..9553496b0f43 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_EFI) += efi.o vars.o
5obj-$(CONFIG_EFI_VARS) += efivars.o 5obj-$(CONFIG_EFI_VARS) += efivars.o
6obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o 6obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
7obj-$(CONFIG_UEFI_CPER) += cper.o 7obj-$(CONFIG_UEFI_CPER) += cper.o
8obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 2e2fbdec0845..4753bac65279 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -32,6 +32,9 @@ struct efi __read_mostly efi = {
32 .hcdp = EFI_INVALID_TABLE_ADDR, 32 .hcdp = EFI_INVALID_TABLE_ADDR,
33 .uga = EFI_INVALID_TABLE_ADDR, 33 .uga = EFI_INVALID_TABLE_ADDR,
34 .uv_systab = EFI_INVALID_TABLE_ADDR, 34 .uv_systab = EFI_INVALID_TABLE_ADDR,
35 .fw_vendor = EFI_INVALID_TABLE_ADDR,
36 .runtime = EFI_INVALID_TABLE_ADDR,
37 .config_table = EFI_INVALID_TABLE_ADDR,
35}; 38};
36EXPORT_SYMBOL(efi); 39EXPORT_SYMBOL(efi);
37 40
@@ -71,13 +74,49 @@ static ssize_t systab_show(struct kobject *kobj,
71static struct kobj_attribute efi_attr_systab = 74static struct kobj_attribute efi_attr_systab =
72 __ATTR(systab, 0400, systab_show, NULL); 75 __ATTR(systab, 0400, systab_show, NULL);
73 76
77#define EFI_FIELD(var) efi.var
78
79#define EFI_ATTR_SHOW(name) \
80static ssize_t name##_show(struct kobject *kobj, \
81 struct kobj_attribute *attr, char *buf) \
82{ \
83 return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
84}
85
86EFI_ATTR_SHOW(fw_vendor);
87EFI_ATTR_SHOW(runtime);
88EFI_ATTR_SHOW(config_table);
89
90static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
91static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
92static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
93
74static struct attribute *efi_subsys_attrs[] = { 94static struct attribute *efi_subsys_attrs[] = {
75 &efi_attr_systab.attr, 95 &efi_attr_systab.attr,
76 NULL, /* maybe more in the future? */ 96 &efi_attr_fw_vendor.attr,
97 &efi_attr_runtime.attr,
98 &efi_attr_config_table.attr,
99 NULL,
77}; 100};
78 101
102static umode_t efi_attr_is_visible(struct kobject *kobj,
103 struct attribute *attr, int n)
104{
105 umode_t mode = attr->mode;
106
107 if (attr == &efi_attr_fw_vendor.attr)
108 return (efi.fw_vendor == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
109 else if (attr == &efi_attr_runtime.attr)
110 return (efi.runtime == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
111 else if (attr == &efi_attr_config_table.attr)
112 return (efi.config_table == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
113
114 return mode;
115}
116
79static struct attribute_group efi_subsys_attr_group = { 117static struct attribute_group efi_subsys_attr_group = {
80 .attrs = efi_subsys_attrs, 118 .attrs = efi_subsys_attrs,
119 .is_visible = efi_attr_is_visible,
81}; 120};
82 121
83static struct efivars generic_efivars; 122static struct efivars generic_efivars;
@@ -128,6 +167,10 @@ static int __init efisubsys_init(void)
128 goto err_unregister; 167 goto err_unregister;
129 } 168 }
130 169
170 error = efi_runtime_map_init(efi_kobj);
171 if (error)
172 goto err_remove_group;
173
131 /* and the standard mountpoint for efivarfs */ 174 /* and the standard mountpoint for efivarfs */
132 efivars_kobj = kobject_create_and_add("efivars", efi_kobj); 175 efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
133 if (!efivars_kobj) { 176 if (!efivars_kobj) {
diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c
new file mode 100644
index 000000000000..97cdd16a2169
--- /dev/null
+++ b/drivers/firmware/efi/runtime-map.c
@@ -0,0 +1,181 @@
1/*
2 * linux/drivers/efi/runtime-map.c
3 * Copyright (C) 2013 Red Hat, Inc., Dave Young <dyoung@redhat.com>
4 *
5 * This file is released under the GPLv2.
6 */
7
8#include <linux/string.h>
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/types.h>
12#include <linux/efi.h>
13#include <linux/slab.h>
14
15#include <asm/setup.h>
16
17static void *efi_runtime_map;
18static int nr_efi_runtime_map;
19static u32 efi_memdesc_size;
20
21struct efi_runtime_map_entry {
22 efi_memory_desc_t md;
23 struct kobject kobj; /* kobject for each entry */
24};
25
26static struct efi_runtime_map_entry **map_entries;
27
28struct map_attribute {
29 struct attribute attr;
30 ssize_t (*show)(struct efi_runtime_map_entry *entry, char *buf);
31};
32
33static inline struct map_attribute *to_map_attr(struct attribute *attr)
34{
35 return container_of(attr, struct map_attribute, attr);
36}
37
38static ssize_t type_show(struct efi_runtime_map_entry *entry, char *buf)
39{
40 return snprintf(buf, PAGE_SIZE, "0x%x\n", entry->md.type);
41}
42
43#define EFI_RUNTIME_FIELD(var) entry->md.var
44
45#define EFI_RUNTIME_U64_ATTR_SHOW(name) \
46static ssize_t name##_show(struct efi_runtime_map_entry *entry, char *buf) \
47{ \
48 return snprintf(buf, PAGE_SIZE, "0x%llx\n", EFI_RUNTIME_FIELD(name)); \
49}
50
51EFI_RUNTIME_U64_ATTR_SHOW(phys_addr);
52EFI_RUNTIME_U64_ATTR_SHOW(virt_addr);
53EFI_RUNTIME_U64_ATTR_SHOW(num_pages);
54EFI_RUNTIME_U64_ATTR_SHOW(attribute);
55
56static inline struct efi_runtime_map_entry *to_map_entry(struct kobject *kobj)
57{
58 return container_of(kobj, struct efi_runtime_map_entry, kobj);
59}
60
61static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
62 char *buf)
63{
64 struct efi_runtime_map_entry *entry = to_map_entry(kobj);
65 struct map_attribute *map_attr = to_map_attr(attr);
66
67 return map_attr->show(entry, buf);
68}
69
70static struct map_attribute map_type_attr = __ATTR_RO(type);
71static struct map_attribute map_phys_addr_attr = __ATTR_RO(phys_addr);
72static struct map_attribute map_virt_addr_attr = __ATTR_RO(virt_addr);
73static struct map_attribute map_num_pages_attr = __ATTR_RO(num_pages);
74static struct map_attribute map_attribute_attr = __ATTR_RO(attribute);
75
76/*
77 * These are default attributes that are added for every memmap entry.
78 */
79static struct attribute *def_attrs[] = {
80 &map_type_attr.attr,
81 &map_phys_addr_attr.attr,
82 &map_virt_addr_attr.attr,
83 &map_num_pages_attr.attr,
84 &map_attribute_attr.attr,
85 NULL
86};
87
88static const struct sysfs_ops map_attr_ops = {
89 .show = map_attr_show,
90};
91
92static void map_release(struct kobject *kobj)
93{
94 struct efi_runtime_map_entry *entry;
95
96 entry = to_map_entry(kobj);
97 kfree(entry);
98}
99
100static struct kobj_type __refdata map_ktype = {
101 .sysfs_ops = &map_attr_ops,
102 .default_attrs = def_attrs,
103 .release = map_release,
104};
105
106static struct kset *map_kset;
107
108static struct efi_runtime_map_entry *
109add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
110{
111 int ret;
112 struct efi_runtime_map_entry *entry;
113
114 if (!map_kset) {
115 map_kset = kset_create_and_add("runtime-map", NULL, kobj);
116 if (!map_kset)
117 return ERR_PTR(-ENOMEM);
118 }
119
120 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
121 if (!entry) {
122 kset_unregister(map_kset);
123 return entry;
124 }
125
126 memcpy(&entry->md, efi_runtime_map + nr * efi_memdesc_size,
127 sizeof(efi_memory_desc_t));
128
129 kobject_init(&entry->kobj, &map_ktype);
130 entry->kobj.kset = map_kset;
131 ret = kobject_add(&entry->kobj, NULL, "%d", nr);
132 if (ret) {
133 kobject_put(&entry->kobj);
134 kset_unregister(map_kset);
135 return ERR_PTR(ret);
136 }
137
138 return entry;
139}
140
141void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size)
142{
143 efi_runtime_map = map;
144 nr_efi_runtime_map = nr_entries;
145 efi_memdesc_size = desc_size;
146}
147
148int __init efi_runtime_map_init(struct kobject *efi_kobj)
149{
150 int i, j, ret = 0;
151 struct efi_runtime_map_entry *entry;
152
153 if (!efi_runtime_map)
154 return 0;
155
156 map_entries = kzalloc(nr_efi_runtime_map * sizeof(entry), GFP_KERNEL);
157 if (!map_entries) {
158 ret = -ENOMEM;
159 goto out;
160 }
161
162 for (i = 0; i < nr_efi_runtime_map; i++) {
163 entry = add_sysfs_runtime_map_entry(efi_kobj, i);
164 if (IS_ERR(entry)) {
165 ret = PTR_ERR(entry);
166 goto out_add_entry;
167 }
168 *(map_entries + i) = entry;
169 }
170
171 return 0;
172out_add_entry:
173 for (j = i - 1; j > 0; j--) {
174 entry = *(map_entries + j);
175 kobject_put(&entry->kobj);
176 }
177 if (map_kset)
178 kset_unregister(map_kset);
179out:
180 return ret;
181}