Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dave Young and committed by
Matt Fleming
926172d4 a0998eb1

+287 -3
+34
Documentation/ABI/testing/sysfs-firmware-efi-runtime-map
··· 1 + What: /sys/firmware/efi/runtime-map/ 2 + Date: December 2013 3 + Contact: Dave Young <dyoung@redhat.com> 4 + Description: 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. 34 + Users: Kexec
+43 -3
arch/x86/platform/efi/efi.c
··· 76 76 {NULL_GUID, NULL, NULL}, 77 77 }; 78 78 79 + static void *efi_runtime_map; 80 + static int nr_efi_runtime_map; 81 + 79 82 /* 80 83 * Returns 1 if 'facility' is enabled, 0 otherwise. 81 84 */ ··· 827 824 } 828 825 } 829 826 827 + static int __init save_runtime_map(void) 828 + { 829 + efi_memory_desc_t *md; 830 + void *tmp, *p, *q = NULL; 831 + int count = 0; 832 + 833 + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 834 + md = p; 835 + 836 + if (!(md->attribute & EFI_MEMORY_RUNTIME) || 837 + (md->type == EFI_BOOT_SERVICES_CODE) || 838 + (md->type == EFI_BOOT_SERVICES_DATA)) 839 + continue; 840 + tmp = krealloc(q, (count + 1) * memmap.desc_size, GFP_KERNEL); 841 + if (!tmp) 842 + goto out; 843 + q = tmp; 844 + 845 + memcpy(q + count * memmap.desc_size, md, memmap.desc_size); 846 + count++; 847 + } 848 + 849 + efi_runtime_map = q; 850 + nr_efi_runtime_map = count; 851 + efi_runtime_map_setup(efi_runtime_map, nr_efi_runtime_map, 852 + boot_params.efi_info.efi_memdesc_size); 853 + 854 + return 0; 855 + out: 856 + kfree(q); 857 + return -ENOMEM; 858 + } 859 + 830 860 /* 831 861 * Map efi memory ranges for runtime serivce and update new_memmap with virtual 832 862 * addresses. ··· 885 849 tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size, 886 850 GFP_KERNEL); 887 851 if (!tmp) 888 - goto out_krealloc; 852 + goto out; 889 853 new_memmap = tmp; 890 854 memcpy(new_memmap + (*count * memmap.desc_size), md, 891 855 memmap.desc_size); ··· 893 857 } 894 858 895 859 return new_memmap; 896 - out_krealloc: 860 + out: 897 861 kfree(new_memmap); 898 862 return NULL; 899 863 } ··· 919 883 { 920 884 efi_status_t status; 921 885 void *new_memmap = NULL; 922 - int count = 0; 886 + int err, count = 0; 923 887 924 888 efi.systab = NULL; 925 889 ··· 939 903 pr_err("Error reallocating memory, EFI runtime non-functional!\n"); 940 904 return; 941 905 } 906 + 907 + err = save_runtime_map(); 908 + if (err) 909 + pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n"); 942 910 943 911 BUG_ON(!efi.systab); 944 912
+11
drivers/firmware/efi/Kconfig
··· 39 39 config UEFI_CPER 40 40 def_bool n 41 41 42 + config 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 + 42 53 endmenu
+1
drivers/firmware/efi/Makefile
··· 5 5 obj-$(CONFIG_EFI_VARS) += efivars.o 6 6 obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o 7 7 obj-$(CONFIG_UEFI_CPER) += cper.o 8 + obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
+4
drivers/firmware/efi/efi.c
··· 167 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 174 /* and the standard mountpoint for efivarfs */ 171 175 efivars_kobj = kobject_create_and_add("efivars", efi_kobj); 172 176 if (!efivars_kobj) {
+181
drivers/firmware/efi/runtime-map.c
··· 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 + 17 + static void *efi_runtime_map; 18 + static int nr_efi_runtime_map; 19 + static u32 efi_memdesc_size; 20 + 21 + struct efi_runtime_map_entry { 22 + efi_memory_desc_t md; 23 + struct kobject kobj; /* kobject for each entry */ 24 + }; 25 + 26 + static struct efi_runtime_map_entry **map_entries; 27 + 28 + struct map_attribute { 29 + struct attribute attr; 30 + ssize_t (*show)(struct efi_runtime_map_entry *entry, char *buf); 31 + }; 32 + 33 + static inline struct map_attribute *to_map_attr(struct attribute *attr) 34 + { 35 + return container_of(attr, struct map_attribute, attr); 36 + } 37 + 38 + static 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) \ 46 + static 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 + 51 + EFI_RUNTIME_U64_ATTR_SHOW(phys_addr); 52 + EFI_RUNTIME_U64_ATTR_SHOW(virt_addr); 53 + EFI_RUNTIME_U64_ATTR_SHOW(num_pages); 54 + EFI_RUNTIME_U64_ATTR_SHOW(attribute); 55 + 56 + static 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 + 61 + static 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 + 70 + static struct map_attribute map_type_attr = __ATTR_RO(type); 71 + static struct map_attribute map_phys_addr_attr = __ATTR_RO(phys_addr); 72 + static struct map_attribute map_virt_addr_attr = __ATTR_RO(virt_addr); 73 + static struct map_attribute map_num_pages_attr = __ATTR_RO(num_pages); 74 + static struct map_attribute map_attribute_attr = __ATTR_RO(attribute); 75 + 76 + /* 77 + * These are default attributes that are added for every memmap entry. 78 + */ 79 + static 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 + 88 + static const struct sysfs_ops map_attr_ops = { 89 + .show = map_attr_show, 90 + }; 91 + 92 + static 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 + 100 + static struct kobj_type __refdata map_ktype = { 101 + .sysfs_ops = &map_attr_ops, 102 + .default_attrs = def_attrs, 103 + .release = map_release, 104 + }; 105 + 106 + static struct kset *map_kset; 107 + 108 + static struct efi_runtime_map_entry * 109 + add_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 + 141 + void 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 + 148 + int __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; 172 + out_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); 179 + out: 180 + return ret; 181 + }
+13
include/linux/efi.h
··· 872 872 873 873 #endif /* CONFIG_EFI_VARS */ 874 874 875 + #ifdef CONFIG_EFI_RUNTIME_MAP 876 + int efi_runtime_map_init(struct kobject *); 877 + void efi_runtime_map_setup(void *, int, u32); 878 + #else 879 + static inline int efi_runtime_map_init(struct kobject *kobj) 880 + { 881 + return 0; 882 + } 883 + 884 + static inline void 885 + efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {} 886 + #endif 887 + 875 888 #endif /* _LINUX_EFI_H */