diff options
| author | Vivek Goyal <vgoyal@redhat.com> | 2014-08-08 17:26:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-08 18:57:33 -0400 |
| commit | 6a2c20e7d8900ed273dc34a9af9bf02fc478e427 (patch) | |
| tree | d4825b15aa4b9fd6cc92d4fb107d920544a4548b | |
| parent | dd5f726076cc7639d9713b334c8c133f77c6757a (diff) | |
kexec: support kexec/kdump on EFI systems
This patch does two things. It passes EFI run time mappings to second
kernel in bootparams efi_info. Second kernel parse this info and create
new mappings in second kernel. That means mappings in first and second
kernel will be same. This paves the way to enable EFI in kexec kernel.
This patch also prepares and passes EFI setup data through bootparams.
This contains bunch of information about various tables and their
addresses.
These information gathering and passing has been written along the lines
of what current kexec-tools is doing to make kexec work with UEFI.
[akpm@linux-foundation.org: s/get_efi/efi_get/g, per Matt]
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Greg Kroah-Hartman <greg@kroah.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: WANG Chao <chaowang@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Matt Fleming <matt@console-pimps.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | arch/x86/kernel/kexec-bzimage64.c | 146 | ||||
| -rw-r--r-- | drivers/firmware/efi/runtime-map.c | 21 | ||||
| -rw-r--r-- | include/linux/efi.h | 19 |
3 files changed, 174 insertions, 12 deletions
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index a8e646458a10..623e6c58081f 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c | |||
| @@ -18,10 +18,12 @@ | |||
| 18 | #include <linux/kexec.h> | 18 | #include <linux/kexec.h> |
| 19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
| 20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
| 21 | #include <linux/efi.h> | ||
| 21 | 22 | ||
| 22 | #include <asm/bootparam.h> | 23 | #include <asm/bootparam.h> |
| 23 | #include <asm/setup.h> | 24 | #include <asm/setup.h> |
| 24 | #include <asm/crash.h> | 25 | #include <asm/crash.h> |
| 26 | #include <asm/efi.h> | ||
| 25 | 27 | ||
| 26 | #define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */ | 28 | #define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */ |
| 27 | 29 | ||
| @@ -90,7 +92,7 @@ static int setup_cmdline(struct kimage *image, struct boot_params *params, | |||
| 90 | return 0; | 92 | return 0; |
| 91 | } | 93 | } |
| 92 | 94 | ||
| 93 | static int setup_memory_map_entries(struct boot_params *params) | 95 | static int setup_e820_entries(struct boot_params *params) |
| 94 | { | 96 | { |
| 95 | unsigned int nr_e820_entries; | 97 | unsigned int nr_e820_entries; |
| 96 | 98 | ||
| @@ -107,8 +109,93 @@ static int setup_memory_map_entries(struct boot_params *params) | |||
| 107 | return 0; | 109 | return 0; |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | static int setup_boot_parameters(struct kimage *image, | 112 | #ifdef CONFIG_EFI |
| 111 | struct boot_params *params) | 113 | static int setup_efi_info_memmap(struct boot_params *params, |
| 114 | unsigned long params_load_addr, | ||
| 115 | unsigned int efi_map_offset, | ||
| 116 | unsigned int efi_map_sz) | ||
| 117 | { | ||
| 118 | void *efi_map = (void *)params + efi_map_offset; | ||
| 119 | unsigned long efi_map_phys_addr = params_load_addr + efi_map_offset; | ||
| 120 | struct efi_info *ei = ¶ms->efi_info; | ||
| 121 | |||
| 122 | if (!efi_map_sz) | ||
| 123 | return 0; | ||
| 124 | |||
| 125 | efi_runtime_map_copy(efi_map, efi_map_sz); | ||
| 126 | |||
| 127 | ei->efi_memmap = efi_map_phys_addr & 0xffffffff; | ||
| 128 | ei->efi_memmap_hi = efi_map_phys_addr >> 32; | ||
| 129 | ei->efi_memmap_size = efi_map_sz; | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int | ||
| 135 | prepare_add_efi_setup_data(struct boot_params *params, | ||
| 136 | unsigned long params_load_addr, | ||
| 137 | unsigned int efi_setup_data_offset) | ||
| 138 | { | ||
| 139 | unsigned long setup_data_phys; | ||
| 140 | struct setup_data *sd = (void *)params + efi_setup_data_offset; | ||
| 141 | struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data); | ||
| 142 | |||
| 143 | esd->fw_vendor = efi.fw_vendor; | ||
| 144 | esd->runtime = efi.runtime; | ||
| 145 | esd->tables = efi.config_table; | ||
| 146 | esd->smbios = efi.smbios; | ||
| 147 | |||
| 148 | sd->type = SETUP_EFI; | ||
| 149 | sd->len = sizeof(struct efi_setup_data); | ||
| 150 | |||
| 151 | /* Add setup data */ | ||
| 152 | setup_data_phys = params_load_addr + efi_setup_data_offset; | ||
| 153 | sd->next = params->hdr.setup_data; | ||
| 154 | params->hdr.setup_data = setup_data_phys; | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | static int | ||
| 160 | setup_efi_state(struct boot_params *params, unsigned long params_load_addr, | ||
| 161 | unsigned int efi_map_offset, unsigned int efi_map_sz, | ||
| 162 | unsigned int efi_setup_data_offset) | ||
| 163 | { | ||
| 164 | struct efi_info *current_ei = &boot_params.efi_info; | ||
| 165 | struct efi_info *ei = ¶ms->efi_info; | ||
| 166 | |||
| 167 | if (!current_ei->efi_memmap_size) | ||
| 168 | return 0; | ||
| 169 | |||
| 170 | /* | ||
| 171 | * If 1:1 mapping is not enabled, second kernel can not setup EFI | ||
| 172 | * and use EFI run time services. User space will have to pass | ||
| 173 | * acpi_rsdp=<addr> on kernel command line to make second kernel boot | ||
| 174 | * without efi. | ||
| 175 | */ | ||
| 176 | if (efi_enabled(EFI_OLD_MEMMAP)) | ||
| 177 | return 0; | ||
| 178 | |||
| 179 | ei->efi_loader_signature = current_ei->efi_loader_signature; | ||
| 180 | ei->efi_systab = current_ei->efi_systab; | ||
| 181 | ei->efi_systab_hi = current_ei->efi_systab_hi; | ||
| 182 | |||
| 183 | ei->efi_memdesc_version = current_ei->efi_memdesc_version; | ||
| 184 | ei->efi_memdesc_size = efi_get_runtime_map_desc_size(); | ||
| 185 | |||
| 186 | setup_efi_info_memmap(params, params_load_addr, efi_map_offset, | ||
| 187 | efi_map_sz); | ||
| 188 | prepare_add_efi_setup_data(params, params_load_addr, | ||
| 189 | efi_setup_data_offset); | ||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | #endif /* CONFIG_EFI */ | ||
| 193 | |||
| 194 | static int | ||
| 195 | setup_boot_parameters(struct kimage *image, struct boot_params *params, | ||
| 196 | unsigned long params_load_addr, | ||
| 197 | unsigned int efi_map_offset, unsigned int efi_map_sz, | ||
| 198 | unsigned int efi_setup_data_offset) | ||
| 112 | { | 199 | { |
| 113 | unsigned int nr_e820_entries; | 200 | unsigned int nr_e820_entries; |
| 114 | unsigned long long mem_k, start, end; | 201 | unsigned long long mem_k, start, end; |
| @@ -140,7 +227,7 @@ static int setup_boot_parameters(struct kimage *image, | |||
| 140 | if (ret) | 227 | if (ret) |
| 141 | return ret; | 228 | return ret; |
| 142 | } else | 229 | } else |
| 143 | setup_memory_map_entries(params); | 230 | setup_e820_entries(params); |
| 144 | 231 | ||
| 145 | nr_e820_entries = params->e820_entries; | 232 | nr_e820_entries = params->e820_entries; |
| 146 | 233 | ||
| @@ -161,6 +248,12 @@ static int setup_boot_parameters(struct kimage *image, | |||
| 161 | } | 248 | } |
| 162 | } | 249 | } |
| 163 | 250 | ||
| 251 | #ifdef CONFIG_EFI | ||
| 252 | /* Setup EFI state */ | ||
| 253 | setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz, | ||
| 254 | efi_setup_data_offset); | ||
| 255 | #endif | ||
| 256 | |||
| 164 | /* Setup EDD info */ | 257 | /* Setup EDD info */ |
| 165 | memcpy(params->eddbuf, boot_params.eddbuf, | 258 | memcpy(params->eddbuf, boot_params.eddbuf, |
| 166 | EDDMAXNR * sizeof(struct edd_info)); | 259 | EDDMAXNR * sizeof(struct edd_info)); |
| @@ -214,6 +307,15 @@ int bzImage64_probe(const char *buf, unsigned long len) | |||
| 214 | return ret; | 307 | return ret; |
| 215 | } | 308 | } |
| 216 | 309 | ||
| 310 | /* | ||
| 311 | * Can't handle 32bit EFI as it does not allow loading kernel | ||
| 312 | * above 4G. This should be handled by 32bit bzImage loader | ||
| 313 | */ | ||
| 314 | if (efi_enabled(EFI_RUNTIME_SERVICES) && !efi_enabled(EFI_64BIT)) { | ||
| 315 | pr_debug("EFI is 32 bit. Can't load kernel above 4G.\n"); | ||
| 316 | return ret; | ||
| 317 | } | ||
| 318 | |||
| 217 | /* I've got a bzImage */ | 319 | /* I've got a bzImage */ |
| 218 | pr_debug("It's a relocatable bzImage64\n"); | 320 | pr_debug("It's a relocatable bzImage64\n"); |
| 219 | ret = 0; | 321 | ret = 0; |
| @@ -229,7 +331,7 @@ void *bzImage64_load(struct kimage *image, char *kernel, | |||
| 229 | 331 | ||
| 230 | struct setup_header *header; | 332 | struct setup_header *header; |
| 231 | int setup_sects, kern16_size, ret = 0; | 333 | int setup_sects, kern16_size, ret = 0; |
| 232 | unsigned long setup_header_size, params_cmdline_sz; | 334 | unsigned long setup_header_size, params_cmdline_sz, params_misc_sz; |
| 233 | struct boot_params *params; | 335 | struct boot_params *params; |
| 234 | unsi | ||
