Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4cd9d6f7 authored by Richard Purdie's avatar Richard Purdie Committed by Russell King
Browse files

[ARM] 4736/1: Export atags to userspace and allow kexec to use customised atags



Currently, the atags used by kexec are fixed to the ones originally used
to boot the kernel. This is less than ideal as changing the commandline,
initrd and other options would be a useful feature.

This patch exports the atags used for the current kernel to userspace
through an "atags" file in procfs. The presence of the file is
controlled by its own Kconfig option and cleans up several ifdef blocks
into a separate file. The tags for the new kernel are assumed to be at
a fixed location before the kernel image itself. The location of the
tags used to boot the original kernel is unimportant and no longer
saved.

Based on a patch from Uli Luckas <u.luckas@road.de>

Signed-off-by: default avatarRichard Purdie <rpurdie@rpsys.net>
Acked-by: default avatarUli Luckas <u.luckas@road.de>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent ae9458d6
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -894,6 +894,13 @@ config KEXEC
	  initially work for you.  It may help to enable device hotplugging
	  initially work for you.  It may help to enable device hotplugging
	  support.
	  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
endmenu


if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
+1 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_SMP)		+= smp.o
obj-$(CONFIG_SMP)		+= smp.o
obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-decode.o
obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-decode.o
obj-$(CONFIG_ATAGS_PROC)	+= atags.o
obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o


obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
+86 −0
Original line number Original line Diff line number Diff line
#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);
+5 −0
Original line number Original line Diff line number Diff line
#ifdef CONFIG_ATAGS_PROC
extern void save_atags(struct tag *tags);
#else
static inline void save_atags(struct tag *tags) { }
#endif
+2 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ extern void setup_mm_for_reboot(char mode);
extern unsigned long kexec_start_address;
extern unsigned long kexec_start_address;
extern unsigned long kexec_indirection_page;
extern unsigned long kexec_indirection_page;
extern unsigned long kexec_mach_type;
extern unsigned long kexec_mach_type;
extern unsigned long kexec_boot_atags;


/*
/*
 * Provide a dummy crash_notes definition while crash dump arrives to arm.
 * Provide a dummy crash_notes definition while crash dump arrives to arm.
@@ -62,6 +63,7 @@ void machine_kexec(struct kimage *image)
	kexec_start_address = image->start;
	kexec_start_address = image->start;
	kexec_indirection_page = page_list;
	kexec_indirection_page = page_list;
	kexec_mach_type = machine_arch_type;
	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 */
	/* copy our kernel relocation code to the control code page */
	memcpy(reboot_code_buffer,
	memcpy(reboot_code_buffer,
Loading