aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2014-08-08 17:26:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 18:57:33 -0400
commit6a2c20e7d8900ed273dc34a9af9bf02fc478e427 (patch)
treed4825b15aa4b9fd6cc92d4fb107d920544a4548b
parentdd5f726076cc7639d9713b334c8c133f77c6757a (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.c146
-rw-r--r--drivers/firmware/efi/runtime-map.c21
-rw-r--r--include/linux/efi.h19
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
93static int setup_memory_map_entries(struct boot_params *params) 95static 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
110static int setup_boot_parameters(struct kimage *image, 112#ifdef CONFIG_EFI
111 struct boot_params *params) 113static 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 = &params->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
134static int
135prepare_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
159static int
160setup_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 = &params->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
194static int
195setup_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 unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr; 336 unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr;
235 unsigned long purgatory_load_addr; 337 unsigned long purgatory_load_addr;
@@ -239,6 +341,7 @@ void *bzImage64_load(struct kimage *image, char *kernel,
239 struct kexec_entry64_regs regs64; 341 struct kexec_entry64_regs regs64;
240 void *stack; 342 void *stack;
241 unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr); 343 unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr);
344 unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset;
242 345
243 header = (struct setup_header *)(kernel + setup_hdr_offset); 346 header = (struct setup_header *)(kernel + setup_hdr_offset);
244 setup_sects = header->setup_sects; 347 setup_sects = header->setup_sects;
@@ -285,12 +388,29 @@ void *bzImage64_load(struct kimage *image, char *kernel,
285 388
286 pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); 389 pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr);
287 390
288 /* Load Bootparams and cmdline */ 391
392 /*
393 * Load Bootparams and cmdline and space for efi stuff.
394 *
395 * Allocate memory together for multiple data structures so
396 * that they all can go in single area/segment and we don't
397 * have to create separate segment for each. Keeps things
398 * little bit simple
399 */
400 efi_map_sz = efi_get_runtime_map_size();
401 efi_map_sz = ALIGN(efi_map_sz, 16);
289 params_cmdline_sz = sizeof(struct boot_params) + cmdline_len + 402 params_cmdline_sz = sizeof(struct boot_params) + cmdline_len +
290 MAX_ELFCOREHDR_STR_LEN; 403 MAX_ELFCOREHDR_STR_LEN;
291 params = kzalloc(params_cmdline_sz, GFP_KERNEL); 404 params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
405 params_misc_sz = params_cmdline_sz + efi_map_sz +
406 sizeof(struct setup_data) +
407 sizeof(struct efi_setup_data);
408
409 params = kzalloc(params_misc_sz, GFP_KERNEL);
292 if (!params) 410 if (!params)
293 return ERR_PTR(-ENOMEM); 411 return ERR_PTR(-ENOMEM);
412 efi_map_offset = params_cmdline_sz;
413 efi_setup_data_offset = efi_map_offset + efi_map_sz;
294 414
295 /* Copy setup header onto bootparams. Documentation/x86/boot.txt */ 415 /* Copy setup header onto bootparams. Documentation/x86/boot.txt */
296 setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset; 416 setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset;
@@ -298,13 +418,13 @@ void *bzImage64_load(struct kimage *image, char *kernel,
298 /* Is there a limit on setup header size? */ 418 /* Is there a limit on setup header size? */
299 memcpy(&params->hdr, (kernel + setup_hdr_offset), setup_header_size); 419 memcpy(&params->hdr, (kernel + setup_hdr_offset), setup_header_size);
300 420
301 ret = kexec_add_buffer(image, (char *)params, params_cmdline_sz, 421 ret = kexec_add_buffer(image, (char *)params, params_misc_sz,
302 params_cmdline_sz, 16, MIN_BOOTPARAM_ADDR, 422 params_misc_sz, 16, MIN_BOOTPARAM_ADDR,
303 ULONG_MAX, 1, &bootparam_load_addr); 423 ULONG_MAX, 1, &bootparam_load_addr);
304 if (ret) 424 if (ret)
305 goto out_free_params; 425 goto out_free_params;
306 pr_debug("Loaded boot_param and command line at 0x%lx bufsz=0x%lx memsz=0x%lx\n", 426 pr_debug("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
307 bootparam_load_addr, params_cmdline_sz, params_cmdline_sz); 427 bootparam_load_addr, params_misc_sz, params_misc_sz);
308 428
309 /* Load kernel */ 429 /* Load kernel */
310 kernel_buf = kernel + kern16_size; 430 kernel_buf = kernel + kern16_size;
@@ -365,7 +485,9 @@ void *bzImage64_load(struct kimage *image, char *kernel,
365 if (ret) 485 if (ret)
366 goto out_free_params; 486 goto out_free_params;
367 487
368 ret = setup_boot_parameters(image, params); 488 ret = setup_boot_parameters(image, params, bootparam_load_addr,
489 efi_map_offset, efi_map_sz,
490 efi_setup_data_offset);
369 if (ret) 491 if (ret)
370 goto out_free_params; 492 goto out_free_params;
371 493
diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c
index 97cdd16a2169..018c29a26615 100644
--- a/drivers/firmware/efi/runtime-map.c
+++ b/drivers/firmware/efi/runtime-map.c
@@ -138,6 +138,27 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
138 return entry; 138 return entry;
139} 139}
140 140
141int efi_get_runtime_map_size(void)
142{
143 return nr_efi_runtime_map * efi_memdesc_size;
144}
145
146int efi_get_runtime_map_desc_size(void)
147{
148 return efi_memdesc_size;
149}
150
151int efi_runtime_map_copy(void *buf, size_t bufsz)
152{
153 size_t sz = efi_get_runtime_map_size();
154
155 if (sz > bufsz)
156 sz = bufsz;
157
158 memcpy(buf, efi_runtime_map, sz);
159 return 0;
160}
161
141void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) 162void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size)
142{ 163{
143 efi_runtime_map = map; 164 efi_runtime_map = map;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index efc681fd5895..45cb4ffdea62 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1156,6 +1156,9 @@ int efivars_sysfs_init(void);
1156#ifdef CONFIG_EFI_RUNTIME_MAP 1156#ifdef CONFIG_EFI_RUNTIME_MAP
1157int efi_runtime_map_init(struct kobject *); 1157int efi_runtime_map_init(struct kobject *);
1158void efi_runtime_map_setup(void *, int, u32); 1158void efi_runtime_map_setup(void *, int, u32);
1159int efi_get_runtime_map_size(void);
1160int efi_get_runtime_map_desc_size(void);
1161int efi_runtime_map_copy(void *buf, size_t bufsz);
1159#else 1162#else
1160static inline int efi_runtime_map_init(struct kobject *kobj) 1163static inline int efi_runtime_map_init(struct kobject *kobj)
1161{ 1164{
@@ -1164,6 +1167,22 @@ static inline int efi_runtime_map_init(struct kobject *kobj)
1164 1167
1165static inline void 1168static inline void
1166efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {} 1169efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {}
1170
1171static inline int efi_get_runtime_map_size(void)
1172{
1173 return 0;
1174}
1175
1176static inline int efi_get_runtime_map_desc_size(void)
1177{
1178 return 0;
1179}
1180
1181static inline int efi_runtime_map_copy(void *buf, size_t bufsz)
1182{
1183 return 0;
1184}
1185
1167#endif 1186#endif
1168 1187
1169/* prototypes shared between arch specific and generic stub code */ 1188/* prototypes shared between arch specific and generic stub code */