aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-efi-runtime-map34
-rw-r--r--arch/x86/platform/efi/efi.c46
-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
-rw-r--r--include/linux/efi.h13
7 files changed, 287 insertions, 3 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-efi-runtime-map b/Documentation/ABI/testing/sysfs-firmware-efi-runtime-map
new file mode 100644
index 000000000000..c61b9b348e99
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-efi-runtime-map
@@ -0,0 +1,34 @@
1What: /sys/firmware/efi/runtime-map/
2Date: December 2013
3Contact: Dave Young <dyoung@redhat.com>
4Description: Switching efi runtime services to virtual mode requires
5 that all efi memory ranges which have the runtime attribute
6 bit set to be mapped to virtual addresses.
7
8 The efi runtime services can only be switched to virtual
9 mode once without rebooting. The kexec kernel must maintain
10 the same physical to virtual address mappings as the first
11 kernel. The mappings are exported to sysfs so userspace tools
12 can reassemble them and pass them into the kexec kernel.
13
14 /sys/firmware/efi/runtime-map/ is the directory the kernel
15 exports that information in.
16
17 subdirectories are named with the number of the memory range:
18
19 /sys/firmware/efi/runtime-map/0
20 /sys/firmware/efi/runtime-map/1
21 /sys/firmware/efi/runtime-map/2
22 /sys/firmware/efi/runtime-map/3
23 ...
24
25 Each subdirectory contains five files:
26
27 attribute : The attributes of the memory range.
28 num_pages : The size of the memory range in pages.
29 phys_addr : The physical address of the memory range.
30 type : The type of the memory range.
31 virt_addr : The virtual address of the memory range.
32
33 Above values are all hexadecimal numbers with the '0x' prefix.
34Users: Kexec
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 28591072fbb7..74fe7a719508 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -76,6 +76,9 @@ static __initdata efi_config_table_type_t arch_tables[] = {
76 {NULL_GUID, NULL, NULL}, 76 {NULL_GUID, NULL, NULL},
77}; 77};
78 78
79static void *efi_runtime_map;
80static int nr_efi_runtime_map;
81
79/* 82/*
80 * Returns 1 if 'facility' is enabled, 0 otherwise. 83 * Returns 1 if 'facility' is enabled, 0 otherwise.
81 */ 84 */
@@ -824,6 +827,39 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
824 } 827 }
825} 828}
826 829
830static int __init save_runtime_map(void)
831{
832 efi_memory_desc_t *md;
833 void *tmp, *p, *q = NULL;
834 int count = 0;
835
836 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
837 md = p;
838
839 if (!(md->attribute & EFI_MEMORY_RUNTIME) ||
840 (md->type == EFI_BOOT_SERVICES_CODE) ||
841 (md->type == EFI_BOOT_SERVICES_DATA))
842 continue;
843 tmp = krealloc(q, (count + 1) * memmap.desc_size, GFP_KERNEL);
844 if (!tmp)
845 goto out;
846 q = tmp;
847
848 memcpy(q + count * memmap.desc_size, md, memmap.desc_size);
849 count++;
850 }
851
852 efi_runtime_map = q;
853 nr_efi_runtime_map = count;
854 efi_runtime_map_setup(efi_runtime_map, nr_efi_runtime_map,
855 boot_params.efi_info.efi_memdesc_size);
856
857 return 0;
858out:
859 kfree(q);
860 return -ENOMEM;
861}
862
827/* 863/*
828 * Map efi memory ranges for runtime serivce and update new_memmap with virtual 864 * Map efi memory ranges for runtime serivce and update new_memmap with virtual
829 * addresses. 865 * addresses.
@@ -849,7 +885,7 @@ static void * __init efi_map_regions(int *count)
849 tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size, 885 tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size,
850 GFP_KERNEL); 886 GFP_KERNEL);
851 if (!tmp) 887 if (!tmp)
852 goto out_krealloc; 888 goto out;
853 new_memmap = tmp; 889 new_memmap = tmp;
854 memcpy(new_memmap + (*count * memmap.desc_size), md, 890 memcpy(new_memmap + (*count * memmap.desc_size), md,
855 memmap.desc_size); 891 memmap.desc_size);
@@ -857,7 +893,7 @@ static void * __init efi_map_regions(int *count)
857 } 893 }
858 894
859 return new_memmap; 895 return new_memmap;
860out_krealloc: 896out:
861 kfree(new_memmap); 897 kfree(new_memmap);
862 return NULL; 898 return NULL;
863} 899}
@@ -883,7 +919,7 @@ void __init efi_enter_virtual_mode(void)
883{ 919{
884 efi_status_t status; 920 efi_status_t status;
885 void *new_memmap = NULL; 921 void *new_memmap = NULL;
886 int count = 0; 922 int err, count = 0;
887 923
888 efi.systab = NULL; 924 efi.systab = NULL;
889 925
@@ -904,6 +940,10 @@ void __init efi_enter_virtual_mode(void)
904 return; 940 return;
905 } 941 }
906 942
943 err = save_runtime_map();
944 if (err)
945 pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
946
907 BUG_ON(!efi.systab); 947 BUG_ON(!efi.systab);
908 948
909 efi_setup_page_tables(); 949 efi_setup_page_tables();
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}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index fb60b10b7bd9..e64540746c63 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -872,4 +872,17 @@ int efivars_sysfs_init(void);
872 872
873#endif /* CONFIG_EFI_VARS */ 873#endif /* CONFIG_EFI_VARS */
874 874
875#ifdef CONFIG_EFI_RUNTIME_MAP
876int efi_runtime_map_init(struct kobject *);
877void efi_runtime_map_setup(void *, int, u32);
878#else
879static inline int efi_runtime_map_init(struct kobject *kobj)
880{
881 return 0;
882}
883
884static inline void
885efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {}
886#endif
887
875#endif /* _LINUX_EFI_H */ 888#endif /* _LINUX_EFI_H */