aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <magnus@valinux.co.jp>2007-03-06 05:34:26 -0500
committerTony Luck <tony.luck@intel.com>2007-03-06 17:50:33 -0500
commitcee87af2a5f75713b98d3e65e43872e547122cd5 (patch)
tree1b5e4778d66cab374e333b4a327d28b0e037ab3f
parent41d5e5d73ecef4ef56b7b4cde962929a712689b4 (diff)
[IA64] kexec: Use EFI_LOADER_DATA for ELF core header
The address where the ELF core header is stored is passed to the secondary kernel as a kernel command line option. The memory area for this header is also marked as a separate EFI memory descriptor on ia64. The separate EFI memory descriptor is at the moment of the type EFI_UNUSABLE_MEMORY. With such a type the secondary kernel skips over the entire memory granule (config option, 16M or 64M) when detecting memory. If we are lucky we will just lose some memory, but if we happen to have data in the same granule (such as an initramfs image), then this data will never get mapped and the kernel bombs out when trying to access it. So this is an attempt to fix this by changing the EFI memory descriptor type into EFI_LOADER_DATA. This type is the same type used for the kernel data and for initramfs. In the secondary kernel we then handle the ELF core header data the same way as we handle the initramfs image. This patch contains the kernel changes to make this happen. Pretty straightforward, we reserve the area in reserve_memory(). The address for the area comes from the kernel command line and the size comes from the specialized EFI parsing function vmcore_find_descriptor_size(). The kexec-tools-testing code for this can be found here: http://lists.osdl.org/pipermail/fastboot/2007-February/005983.html Signed-off-by: Magnus Damm <magnus@valinux.co.jp> Cc: Simon Horman <horms@verge.net.au> Cc: Vivek Goyal <vgoyal@in.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r--arch/ia64/kernel/efi.c30
-rw-r--r--arch/ia64/kernel/setup.c30
-rw-r--r--include/asm-ia64/meminit.h6
3 files changed, 65 insertions, 1 deletions
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 32ce330cbc64..4061593e5b17 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -1183,3 +1183,33 @@ kdump_find_rsvd_region (unsigned long size,
1183 return ~0UL; 1183 return ~0UL;
1184} 1184}
1185#endif 1185#endif
1186
1187#ifdef CONFIG_PROC_VMCORE
1188/* locate the size find a the descriptor at a certain address */
1189unsigned long
1190vmcore_find_descriptor_size (unsigned long address)
1191{
1192 void *efi_map_start, *efi_map_end, *p;
1193 efi_memory_desc_t *md;
1194 u64 efi_desc_size;
1195 unsigned long ret = 0;
1196
1197 efi_map_start = __va(ia64_boot_param->efi_memmap);
1198 efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
1199 efi_desc_size = ia64_boot_param->efi_memdesc_size;
1200
1201 for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
1202 md = p;
1203 if (efi_wb(md) && md->type == EFI_LOADER_DATA
1204 && md->phys_addr == address) {
1205 ret = efi_md_size(md);
1206 break;
1207 }
1208 }
1209
1210 if (ret == 0)
1211 printk(KERN_WARNING "Cannot locate EFI vmcore descriptor\n");
1212
1213 return ret;
1214}
1215#endif
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 5fa09d141ab7..7d6fe65c93f4 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -251,6 +251,12 @@ reserve_memory (void)
251 } 251 }
252#endif 252#endif
253 253
254#ifdef CONFIG_PROC_VMCORE
255 if (reserve_elfcorehdr(&rsvd_region[n].start,
256 &rsvd_region[n].end) == 0)
257 n++;
258#endif
259
254 efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end); 260 efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end);
255 n++; 261 n++;
256 262
@@ -453,6 +459,30 @@ static int __init parse_elfcorehdr(char *arg)
453 return 0; 459 return 0;
454} 460}
455early_param("elfcorehdr", parse_elfcorehdr); 461early_param("elfcorehdr", parse_elfcorehdr);
462
463int __init reserve_elfcorehdr(unsigned long *start, unsigned long *end)
464{
465 unsigned long length;
466
467 /* We get the address using the kernel command line,
468 * but the size is extracted from the EFI tables.
469 * Both address and size are required for reservation
470 * to work properly.
471 */
472
473 if (elfcorehdr_addr >= ELFCORE_ADDR_MAX)
474 return -EINVAL;
475
476 if ((length = vmcore_find_descriptor_size(elfcorehdr_addr)) == 0) {
477 elfcorehdr_addr = ELFCORE_ADDR_MAX;
478 return -EINVAL;
479 }
480
481 *start = (unsigned long)__va(elfcorehdr_addr);
482 *end = *start + length;
483 return 0;
484}
485
456#endif /* CONFIG_PROC_VMCORE */ 486#endif /* CONFIG_PROC_VMCORE */
457 487
458void __init 488void __init
diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
index 6dd476b652c6..21ec5f3d23de 100644
--- a/include/asm-ia64/meminit.h
+++ b/include/asm-ia64/meminit.h
@@ -17,10 +17,11 @@
17 * - kernel code & data 17 * - kernel code & data
18 * - crash dumping code reserved region 18 * - crash dumping code reserved region
19 * - Kernel memory map built from EFI memory map 19 * - Kernel memory map built from EFI memory map
20 * - ELF core header
20 * 21 *
21 * More could be added if necessary 22 * More could be added if necessary
22 */ 23 */
23#define IA64_MAX_RSVD_REGIONS 7 24#define IA64_MAX_RSVD_REGIONS 8
24 25
25struct rsvd_region { 26struct rsvd_region {
26 unsigned long start; /* virtual address of beginning of element */ 27 unsigned long start; /* virtual address of beginning of element */
@@ -36,6 +37,9 @@ extern void find_initrd (void);
36extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg); 37extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg);
37extern void efi_memmap_init(unsigned long *, unsigned long *); 38extern void efi_memmap_init(unsigned long *, unsigned long *);
38 39
40extern unsigned long vmcore_find_descriptor_size(unsigned long address);
41extern int reserve_elfcorehdr(unsigned long *start, unsigned long *end);
42
39/* 43/*
40 * For rounding an address to the next IA64_GRANULE_SIZE or order 44 * For rounding an address to the next IA64_GRANULE_SIZE or order
41 */ 45 */