aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorDave Young <dyoung@redhat.com>2013-12-20 05:02:18 -0500
committerMatt Fleming <matt.fleming@intel.com>2013-12-21 10:29:36 -0500
commit926172d46038d7610b6b8d84e40db727cefb482d (patch)
tree8963aaa9fccd0a4ee0d59717b4de8e8cdfebbe62 /drivers/firmware
parenta0998eb15afeffbf52a2c2829318f67df9ac57b8 (diff)
efi: Export EFI runtime memory mapping to sysfs
kexec kernel will need exactly same mapping for EFI runtime memory ranges. Thus here export the runtime ranges mapping to sysfs, kexec-tools will assemble them and pass to 2nd kernel via setup_data. Introducing a new directory /sys/firmware/efi/runtime-map just like /sys/firmware/memmap. Containing below attribute in each file of that directory: attribute num_pages phys_addr type virt_addr Signed-off-by: Dave Young <dyoung@redhat.com> Tested-by: Toshi Kani <toshi.kani@hp.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
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.c4
-rw-r--r--drivers/firmware/efi/runtime-map.c181
4 files changed, 197 insertions, 0 deletions
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 3150aa4874e8..730f5f2e8b7f 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -39,4 +39,15 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE
39config UEFI_CPER 39config UEFI_CPER
40 def_bool n 40 def_bool n
41 41
42config EFI_RUNTIME_MAP
43 bool "Export efi runtime maps to sysfs"
44 depends on X86 && EFI && KEXEC
45 default y
46 help
47 Export efi runtime memory maps to /sys/firmware/efi/runtime-map.
48 That memory map is used for example by kexec to set up efi virtual
49 mapping the 2nd kernel, but can also be used for debugging purposes.
50
51 See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
52
42endmenu 53endmenu
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index 9ba156d3c775..a58e0f183a08 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -5,3 +5,4 @@ obj-y += 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 72533af72b98..4753bac65279 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -167,6 +167,10 @@ static int __init efisubsys_init(void)
167 goto err_unregister; 167 goto err_unregister;
168 } 168 }
169 169
170 error = efi_runtime_map_init(efi_kobj);
171 if (error)
172 goto err_remove_group;
173
170 /* and the standard mountpoint for efivarfs */ 174 /* and the standard mountpoint for efivarfs */
171 efivars_kobj = kobject_create_and_add("efivars", efi_kobj); 175 efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
172 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}