Leapfrogged from upstream (ARM Linux)
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4736/1

Index: linux-2.6.24/arch/arm/Kconfig
===================================================================
--- linux-2.6.24.orig/arch/arm/Kconfig
+++ linux-2.6.24/arch/arm/Kconfig
@@ -865,6 +865,13 @@
 	  initially work for you.  It may help to enable device hotplugging
 	  support.
 
+config ATAGS_PROC
+	bool "Export atags in procfs"
+	default n
+	help
+	  Should the atags used to boot the kernel be exported in an "atags"
+	  file in procfs. Useful with kexec.
+
 endmenu
 
 if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
Index: linux-2.6.24/arch/arm/kernel/Makefile
===================================================================
--- linux-2.6.24.orig/arch/arm/kernel/Makefile
+++ linux-2.6.24/arch/arm/kernel/Makefile
@@ -19,6 +19,7 @@
 obj-$(CONFIG_PCI)		+= bios32.o isa.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_ATAGS_PROC)	+= atags.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
Index: linux-2.6.24/arch/arm/kernel/atags.c
===================================================================
--- /dev/null
+++ linux-2.6.24/arch/arm/kernel/atags.c
@@ -0,0 +1,86 @@
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/proc_fs.h>
+#include <asm/setup.h>
+#include <asm/types.h>
+#include <asm/page.h>
+
+struct buffer {
+	size_t size;
+	char *data;
+};
+static struct buffer tags_buffer;
+
+static int
+read_buffer(char* page, char** start, off_t off, int count,
+	int* eof, void* data)
+{
+	struct buffer *buffer = (struct buffer *)data;
+
+	if (off >= buffer->size) {
+		*eof = 1;
+		return 0;
+	}
+
+	count = min((int) (buffer->size - off), count);
+
+	memcpy(page, &buffer->data[off], count);
+
+	return count;
+}
+
+
+static int
+create_proc_entries(void)
+{
+	struct proc_dir_entry* tags_entry;
+
+	tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer);
+	if (!tags_entry)
+		return -ENOMEM;
+
+	return 0;
+}
+
+
+static char __initdata atags_copy_buf[KEXEC_BOOT_PARAMS_SIZE];
+static char __initdata *atags_copy;
+
+void __init save_atags(const struct tag *tags)
+{
+	atags_copy = atags_copy_buf;
+	memcpy(atags_copy, tags, KEXEC_BOOT_PARAMS_SIZE);
+}
+
+
+static int __init init_atags_procfs(void)
+{
+	struct tag *tag;
+	int error;
+
+	if (!atags_copy) {
+		printk(KERN_WARNING "Exporting ATAGs: No saved tags found\n");
+		return -EIO;
+	}
+
+	for (tag = (struct tag *) atags_copy; tag->hdr.size; tag = tag_next(tag))
+		;
+
+	tags_buffer.size = ((char *) tag - atags_copy) + sizeof(tag->hdr);
+	tags_buffer.data = kmalloc(tags_buffer.size, GFP_KERNEL);
+	if (tags_buffer.data == NULL)
+		return -ENOMEM;
+	memcpy(tags_buffer.data, atags_copy, tags_buffer.size);
+
+	error = create_proc_entries();
+	if (error) {
+		printk(KERN_ERR "Exporting ATAGs: not enough memory\n");
+		kfree(tags_buffer.data);
+		tags_buffer.size = 0;
+		tags_buffer.data = NULL;
+	}
+
+	return error;
+}
+
+arch_initcall(init_atags_procfs);
Index: linux-2.6.24/arch/arm/kernel/atags.h
===================================================================
--- /dev/null
+++ linux-2.6.24/arch/arm/kernel/atags.h
@@ -0,0 +1,5 @@
+#ifdef CONFIG_ATAGS_PROC
+extern void save_atags(struct tag *tags);
+#else
+static inline void save_atags(struct tag *tags) { }
+#endif
Index: linux-2.6.24/arch/arm/kernel/machine_kexec.c
===================================================================
--- linux-2.6.24.orig/arch/arm/kernel/machine_kexec.c
+++ linux-2.6.24/arch/arm/kernel/machine_kexec.c
@@ -21,6 +21,7 @@
 extern unsigned long kexec_start_address;
 extern unsigned long kexec_indirection_page;
 extern unsigned long kexec_mach_type;
+extern unsigned long kexec_boot_atags;
 
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
@@ -62,6 +63,7 @@
 	kexec_start_address = image->start;
 	kexec_indirection_page = page_list;
 	kexec_mach_type = machine_arch_type;
+	kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
 
 	/* copy our kernel relocation code to the control code page */
 	memcpy(reboot_code_buffer,
Index: linux-2.6.24/arch/arm/kernel/relocate_kernel.S
===================================================================
--- linux-2.6.24.orig/arch/arm/kernel/relocate_kernel.S
+++ linux-2.6.24/arch/arm/kernel/relocate_kernel.S
@@ -7,23 +7,6 @@
 	.globl relocate_new_kernel
 relocate_new_kernel:
 
-	/* Move boot params back to where the kernel expects them */
-
-	ldr	r0,kexec_boot_params_address
-	teq	r0,#0
-	beq	8f
-
-	ldr	r1,kexec_boot_params_copy
-	mov	r6,#KEXEC_BOOT_PARAMS_SIZE/4
-7:
-	ldr	r5,[r1],#4
-	str	r5,[r0],#4
-	subs	r6,r6,#1
-	bne	7b
-
-8:
-	/* Boot params moved, now go on with the kernel */
-
 	ldr	r0,kexec_indirection_page
 	ldr	r1,kexec_start_address
 
@@ -67,7 +50,7 @@
 	mov lr,r1
 	mov r0,#0
 	ldr r1,kexec_mach_type
-	ldr r2,kexec_boot_params_address
+	ldr r2,kexec_boot_atags
 	mov pc,lr
 
 	.globl kexec_start_address
@@ -82,14 +65,9 @@
 kexec_mach_type:
 	.long	0x0
 
-	/* phy addr where new kernel will expect to find boot params */
-	.globl kexec_boot_params_address
-kexec_boot_params_address:
-	.long	0x0
-
-	/* phy addr where old kernel put a copy of orig boot params */
-	.globl kexec_boot_params_copy
-kexec_boot_params_copy:
+	/* phy addr of the atags for the new kernel */
+	.globl kexec_boot_atags
+kexec_boot_atags:
 	.long	0x0
 
 relocate_new_kernel_end:
Index: linux-2.6.24/arch/arm/kernel/setup.c
===================================================================
--- linux-2.6.24.orig/arch/arm/kernel/setup.c
+++ linux-2.6.24/arch/arm/kernel/setup.c
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/fs.h>
-#include <linux/kexec.h>
 
 #include <asm/cpu.h>
 #include <asm/elf.h>
@@ -39,6 +38,7 @@
 #include <asm/mach/time.h>
 
 #include "compat.h"
+#include "atags.h"
 
 #ifndef MEM_SIZE
 #define MEM_SIZE	(16*1024*1024)
@@ -784,23 +784,6 @@
 }
 arch_initcall(customize_machine);
 
-#ifdef CONFIG_KEXEC
-
-/* Physical addr of where the boot params should be for this machine */
-extern unsigned long kexec_boot_params_address;
-
-/* Physical addr of the buffer into which the boot params are copied */
-extern unsigned long kexec_boot_params_copy;
-
-/* Pointer to the boot params buffer, for manipulation and display */
-unsigned long kexec_boot_params;
-EXPORT_SYMBOL(kexec_boot_params);
-
-/* The buffer itself - make sure it is sized correctly */
-static unsigned long kexec_boot_params_buf[(KEXEC_BOOT_PARAMS_SIZE + 3) / 4];
-
-#endif
-
 void __init setup_arch(char **cmdline_p)
 {
 	struct tag *tags = (struct tag *)&init_tags;
@@ -819,18 +802,6 @@
 	else if (mdesc->boot_params)
 		tags = phys_to_virt(mdesc->boot_params);
 
-#ifdef CONFIG_KEXEC
-	kexec_boot_params_copy = virt_to_phys(kexec_boot_params_buf);
-	kexec_boot_params = (unsigned long)kexec_boot_params_buf;
-	if (__atags_pointer) {
-		kexec_boot_params_address = __atags_pointer;
-		memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
-	} else if (mdesc->boot_params) {
-		kexec_boot_params_address = mdesc->boot_params;
-		memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
-	}
-#endif
-
 	/*
 	 * If we have the old style parameters, convert them to
 	 * a tag list.
@@ -846,6 +817,7 @@
 	if (tags->hdr.tag == ATAG_CORE) {
 		if (meminfo.nr_banks != 0)
 			squash_mem_tags(tags);
+		save_atags(tags);
 		parse_tags(tags);
 	}
 
Index: linux-2.6.24/include/asm-arm/kexec.h
===================================================================
--- linux-2.6.24.orig/include/asm-arm/kexec.h
+++ linux-2.6.24/include/asm-arm/kexec.h
@@ -16,6 +16,9 @@
 
 #define KEXEC_BOOT_PARAMS_SIZE 1536
 
+#define KEXEC_ARM_ATAGS_OFFSET  0x1000
+#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
+
 #ifndef __ASSEMBLY__
 
 struct kimage;
