Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=cee87af2a5f75713b98d3e65e43872e547122cd5
Commit:     cee87af2a5f75713b98d3e65e43872e547122cd5
Parent:     41d5e5d73ecef4ef56b7b4cde962929a712689b4
Author:     Magnus Damm <[EMAIL PROTECTED]>
AuthorDate: Tue Mar 6 02:34:26 2007 -0800
Committer:  Tony Luck <[EMAIL PROTECTED]>
CommitDate: Tue Mar 6 14:50:33 2007 -0800

    [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 <[EMAIL PROTECTED]>
    Cc: Simon Horman <[EMAIL PROTECTED]>
    Cc: Vivek Goyal <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Tony Luck <[EMAIL PROTECTED]>
---
 arch/ia64/kernel/efi.c     |   30 ++++++++++++++++++++++++++++++
 arch/ia64/kernel/setup.c   |   30 ++++++++++++++++++++++++++++++
 include/asm-ia64/meminit.h |    6 +++++-
 3 files changed, 65 insertions(+), 1 deletions(-)

diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 32ce330..4061593 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -1183,3 +1183,33 @@ kdump_find_rsvd_region (unsigned long size,
   return ~0UL;
 }
 #endif
+
+#ifdef CONFIG_PROC_VMCORE
+/* locate the size find a the descriptor at a certain address */
+unsigned long
+vmcore_find_descriptor_size (unsigned long address)
+{
+       void *efi_map_start, *efi_map_end, *p;
+       efi_memory_desc_t *md;
+       u64 efi_desc_size;
+       unsigned long ret = 0;
+
+       efi_map_start = __va(ia64_boot_param->efi_memmap);
+       efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+       efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+       for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+               md = p;
+               if (efi_wb(md) && md->type == EFI_LOADER_DATA
+                   && md->phys_addr == address) {
+                       ret = efi_md_size(md);
+                       break;
+               }
+       }
+
+       if (ret == 0)
+               printk(KERN_WARNING "Cannot locate EFI vmcore descriptor\n");
+
+       return ret;
+}
+#endif
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 5fa09d1..7d6fe65 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -251,6 +251,12 @@ reserve_memory (void)
        }
 #endif
 
+#ifdef CONFIG_PROC_VMCORE
+       if (reserve_elfcorehdr(&rsvd_region[n].start,
+                              &rsvd_region[n].end) == 0)
+               n++;
+#endif
+
        efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end);
        n++;
 
@@ -453,6 +459,30 @@ static int __init parse_elfcorehdr(char *arg)
        return 0;
 }
 early_param("elfcorehdr", parse_elfcorehdr);
+
+int __init reserve_elfcorehdr(unsigned long *start, unsigned long *end)
+{
+       unsigned long length;
+
+       /* We get the address using the kernel command line,
+        * but the size is extracted from the EFI tables.
+        * Both address and size are required for reservation
+        * to work properly.
+        */
+
+       if (elfcorehdr_addr >= ELFCORE_ADDR_MAX)
+               return -EINVAL;
+
+       if ((length = vmcore_find_descriptor_size(elfcorehdr_addr)) == 0) {
+               elfcorehdr_addr = ELFCORE_ADDR_MAX;
+               return -EINVAL;
+       }
+
+       *start = (unsigned long)__va(elfcorehdr_addr);
+       *end = *start + length;
+       return 0;
+}
+
 #endif /* CONFIG_PROC_VMCORE */
 
 void __init
diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
index 6dd476b..21ec5f3 100644
--- a/include/asm-ia64/meminit.h
+++ b/include/asm-ia64/meminit.h
@@ -17,10 +17,11 @@
  *     - kernel code & data
  *     - crash dumping code reserved region
  *     - Kernel memory map built from EFI memory map
+ *     - ELF core header
  *
  * More could be added if necessary
  */
-#define IA64_MAX_RSVD_REGIONS 7
+#define IA64_MAX_RSVD_REGIONS 8
 
 struct rsvd_region {
        unsigned long start;    /* virtual address of beginning of element */
@@ -36,6 +37,9 @@ extern void find_initrd (void);
 extern int filter_rsvd_memory (unsigned long start, unsigned long end, void 
*arg);
 extern void efi_memmap_init(unsigned long *, unsigned long *);
 
+extern unsigned long vmcore_find_descriptor_size(unsigned long address);
+extern int reserve_elfcorehdr(unsigned long *start, unsigned long *end);
+
 /*
  * For rounding an address to the next IA64_GRANULE_SIZE or order
  */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to