[PATCH] some kexec MIPS improvements

Simon Horman horms at verge.net.au
Sun Feb 21 17:41:17 EST 2010


On Thu, Feb 18, 2010 at 06:19:40PM +0300, Maxim Uvarov wrote:
> Hello folks,
> 
> Please take a look at attached patch. We made kexec and crashdump worked on mips platform.
> I hope it will help community to fix mips implementation. This code worked with Cavium Octeon(mips64)
> boards and RMI XLR/XLS (both 32 and 64 bits). Of course if needed kexec code presents in kernel. Because of Octeon boards are supported in linux-mips tree I will try to find time to push kernel changes there. But before it I would like to hear any critics on my changes. Maybe it is better to change something.
> 
> Best regards,
> Maxim Uvarov.

Thanks, very much appreciated.

I've made some minor comments inline below.

> Changes are:
> 
> -  using simple   mips* ) in configure.ac to make it compilable on mips2
> 	and mips64
> - remove kexec/arch/mips/mips-setup-simple.S which prepares cmdline for
> new kernel, it is better to move this work to kernel code. BTW this code was
> compilable only on o32 because of t4 is not defined on 64-64 or n32 MIPS ABIs.

Is the code now present in the kernel, or will it be soon?

> - simple put cmdline as string, kernel code should catch cmdline like this
> int board_kexec_prepare(struct kimage *image)
> {
>     int i;
>     char *bootloader = "kexec";
>     board_boot_desc_ptr->argc = 0;
>     for(i=0;i<image->nr_segments;i++)
>     {
>         printk("segment %d
>         if (!strncmp(bootloader, (char*)image->segment[i].buf,
>                 strlen(bootloader)))
>         {
>             /*
>              * convert command line string to array
>              * of parameters (as bootloader does).
>              */
>             int argc = 0, offt;
>             char *str = (char *)image->segment[i].buf;
>             char *ptr = strchr(str, ' ');
>             while (ptr && (ARGV_MAX_ARGS > argc)) {
>                 *ptr = '\0';
>                 if (ptr[1] != ' ') {
>                     offt = (int)(ptr - str + 1);
>                     boot_desc_ptr->argv[argc] =
>                         image->segment[i].mem + offt;
>                     argc++;
>                 }
>                 ptr = strchr(ptr + 1, ' ');
>             }
>             boot_desc_ptr->argc = argc;
>             break;
>         }
>     }
>    Keep it as string make code simple and more readable.
> - add crashdump support
> - do not redefine syscalls numbers if they defined in system
>  remove fixups for /proc/iomem. If your board provides wrong /proc/iomem please
>  fix kernel, or at least you local version of kexec. No need to support it in
>  main line. At least add option --fake-iomem
> - some minor fixes
> ---
> 
>  configure.ac                        |    2 
>  kexec/arch/mips/Makefile            |    4 
>  kexec/arch/mips/crashdump-mips.c    |  380 +++++++++++++++++++++++++++++++++++
>  kexec/arch/mips/crashdump-mips.h    |   26 ++
>  kexec/arch/mips/kexec-elf-mips.c    |  143 +++++++------
>  kexec/arch/mips/kexec-mips.c        |   48 +---
>  kexec/arch/mips/kexec-mips.h        |    9 +
>  kexec/arch/mips/mips-setup-simple.S |  110 ----------
>  kexec/crashdump.h                   |    2 
>  kexec/kexec-syscall.h               |    2 
>  10 files changed, 515 insertions(+), 211 deletions(-)
>  create mode 100644 kexec/arch/mips/crashdump-mips.c
>  create mode 100644 kexec/arch/mips/crashdump-mips.h
>  delete mode 100644 kexec/arch/mips/mips-setup-simple.S
> 
> diff --git a/configure.ac b/configure.ac
> index a911f8a..88d2e0b 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -39,7 +39,7 @@ case $target_cpu in
>  	sh4|sh4a|sh3|sh )
>  		ARCH="sh"
>  		;;
> -	mips|mipsel )
> +	mips* )
>  		ARCH="mips"
>  		;;
>  	cris|crisv32 )
> diff --git a/kexec/arch/mips/Makefile b/kexec/arch/mips/Makefile
> index f94bd89..831b263 100644
> --- a/kexec/arch/mips/Makefile
> +++ b/kexec/arch/mips/Makefile
> @@ -4,7 +4,7 @@
>  mips_KEXEC_SRCS =  kexec/arch/mips/kexec-mips.c
>  mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-mips.c
>  mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-rel-mips.c
> -mips_KEXEC_SRCS += kexec/arch/mips/mips-setup-simple.S
> +mips_KEXEC_SRCS += kexec/arch/mips/crashdump-mips.c
>  
>  mips_ADD_BUFFER =
>  mips_ADD_SEGMENT =
> @@ -12,5 +12,7 @@ mips_VIRT_TO_PHYS =
>  
>  dist += kexec/arch/mips/Makefile $(mips_KEXEC_SRCS)			\
>  	kexec/arch/mips/kexec-mips.h					\
> +	kexec/arch/mips/crashdump-mips.h				\
>  	kexec/arch/mips/include/arch/options.h
>  
> +CFLAGS +=-Wall -Werror
> diff --git a/kexec/arch/mips/crashdump-mips.c b/kexec/arch/mips/crashdump-mips.c
> new file mode 100644
> index 0000000..e49312b
> --- /dev/null
> +++ b/kexec/arch/mips/crashdump-mips.c
> @@ -0,0 +1,380 @@
> +/*
> + * kexec: Linux boots Linux
> + *
> + * 2005 (C) IBM Corporation.
> + * 2008 (C) MontaVista Software, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation (version 2 of the License).
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <limits.h>
> +#include <elf.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include "../../kexec.h"
> +#include "../../kexec-elf.h"
> +#include "../../kexec-syscall.h"
> +#include "../../crashdump.h"
> +#include "kexec-mips.h"
> +#include "crashdump-mips.h"
> +
> +extern struct arch_options_t arch_options;
> +
> +/* Stores a sorted list of RAM memory ranges for which to create elf headers.
> + * A separate program header is created for backup region */
> +static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
> +
> +/* Memory region reserved for storing panic kernel and other data. */
> +static struct memory_range crash_reserved_mem;
> +
> +/*
> + * To store the memory size of the first kernel and this value will be
> + * passed to the second kernel as command line (savemaxmem=xM).
> + * The second kernel will be calculated saved_max_pfn based on this
> + * variable.
> + */
> +unsigned long long saved_max_mem = 0;
> +
> +/* Removes crash reserve region from list of memory chunks for whom elf program
> + * headers have to be created. Assuming crash reserve region to be a single
> + * continuous area fully contained inside one of the memory chunks */
> +static int exclude_crash_reserve_region(int *nr_ranges)
> +{
> +	int i, j, tidx = -1;
> +	unsigned long long cstart, cend;
> +	struct memory_range temp_region;
> +
> +	/* Crash reserved region. */
> +	cstart = crash_reserved_mem.start;
> +	cend = crash_reserved_mem.end;
> +
> +	for (i = 0; i < (*nr_ranges); i++) {
> +		unsigned long long mstart, mend;
> +		mstart = crash_memory_range[i].start;
> +		mend = crash_memory_range[i].end;
> +		if (cstart < mend && cend > mstart) {
> +			if (cstart != mstart && cend != mend) {
> +				/* Split memory region */
> +				crash_memory_range[i].end = cstart - 1;
> +				temp_region.start = cend + 1;
> +				temp_region.end = mend;
> +				temp_region.type = RANGE_RAM;
> +				tidx = i+1;
> +			} else if (cstart != mstart)
> +				crash_memory_range[i].end = cstart - 1;
> +			else
> +				crash_memory_range[i].start = cend + 1;
> +		}
> +	}
> +	/* Insert split memory region, if any. */
> +	if (tidx >= 0) {
> +		if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) {
> +			/* No space to insert another element. */
> +			fprintf(stderr, "Error: Number of crash memory ranges"
> +					" excedeed the max limit\n");
> +			return -1;
> +		}
> +		for (j = (*nr_ranges - 1); j >= tidx; j--)
> +			crash_memory_range[j+1] = crash_memory_range[j];
> +		crash_memory_range[tidx].start = temp_region.start;
> +		crash_memory_range[tidx].end = temp_region.end;
> +		crash_memory_range[tidx].type = temp_region.type;
> +		(*nr_ranges)++;
> +	}
> +	return 0;
> +}
> +/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
> + * create Elf headers. Keeping it separate from get_memory_ranges() as
> + * requirements are different in the case of normal kexec and crashdumps.
> + *
> + * Normal kexec needs to look at all of available physical memory irrespective
> + * of the fact how much of it is being used by currently running kernel.
> + * Crashdumps need to have access to memory regions actually being used by
> + * running  kernel. Expecting a different file/data structure than /proc/iomem
> + * to look into down the line. May be something like /proc/kernelmem or may
> + * be zone data structures exported from kernel.
> + */
> +static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
> +{
> +	const char iomem[]= "/proc/iomem";
> +	int i, memory_ranges = 0;
> +	char line[MAX_LINE];
> +	FILE *fp;
> +	unsigned long long start, end;
> +
> +	fp = fopen(iomem, "r");
> +	if (!fp) {
> +		fprintf(stderr, "Cannot open %s: %s\n",
> +			iomem, strerror(errno));
> +		return -1;
> +	}
> +	/* Separate segment for backup region */
> +	crash_memory_range[0].start = BACKUP_SRC_START;
> +	crash_memory_range[0].end = BACKUP_SRC_END;
> +	crash_memory_range[0].type = RANGE_RAM;
> +	memory_ranges++;
> +
> +	while(fgets(line, sizeof(line), fp) != 0) {
> +		char *str;
> +		int type, consumed, count;
> +		if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
> +			break;
> +		count = sscanf(line, "%Lx-%Lx : %n",
> +			&start, &end, &consumed);
> +		if (count != 2)
> +			continue;
> +		str = line + consumed;
> +
> +		/* Only Dumping memory of type System RAM. */
> +		if (memcmp(str, "System RAM\n", 11) == 0) {
> +			type = RANGE_RAM;
> +		} else if (memcmp(str, "Crash kernel\n", 13) == 0) {
> +				/* Reserved memory region. New kernel can
> +				 * use this region to boot into. */
> +				crash_reserved_mem.start = start;
> +				crash_reserved_mem.end = end;
> +				crash_reserved_mem.type = RANGE_RAM;
> +				printf("%s() start %llx end %llx\n",
> +						__FUNCTION__, start, end);
> +				continue;
> +		} else {
> +			continue;
> +		}
> +		

The line above has a trailing white-space.

> +		if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1))
> +			start = BACKUP_SRC_END + 1;
> +
> +		crash_memory_range[memory_ranges].start = start;
> +		crash_memory_range[memory_ranges].end = end;
> +		crash_memory_range[memory_ranges].type = type;
> +		memory_ranges++;
> +
> +		/* Segregate linearly mapped region. */
> +		if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) {
> +			crash_memory_range[memory_ranges-1].end = MAXMEM -1;
> +
> +			/* Add segregated region. */
> +			crash_memory_range[memory_ranges].start = MAXMEM;
> +			crash_memory_range[memory_ranges].end = end;
> +			crash_memory_range[memory_ranges].type = type;
> +			memory_ranges++;
> +		}
> +	}
> +	fclose(fp);
> +
> +	if (exclude_crash_reserve_region(&memory_ranges) < 0)
> +		return -1;
> +
> +	for (i = 0; i < memory_ranges; i++)
> +		if (saved_max_mem < crash_memory_range[i].end)
> +			saved_max_mem = crash_memory_range[i].end + 1;
> +
> +	*range = crash_memory_range;
> +	*ranges = memory_ranges;
> +	return 0;
> +}
> +
> +/* Converts unsigned long to ascii string. */
> +static void ultoa(unsigned long i, char *str)
> +{
> +	int j = 0, k;
> +	char tmp;
> +
> +	do {
> +		str[j++] = i % 10 + '0';
> +	} while ((i /=10) > 0);
> +	str[j] = '\0';
> +
> +	/* Reverse the string. */
> +	for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
> +		tmp = str[k];
> +		str[k] = str[j];
> +		str[j] = tmp;
> +	}
> +}
> +
> +/* Adds the appropriate mem= options to command line, indicating the
> + * memory region the new kernel can use to boot into. */
> +static int cmdline_add_mem(char *cmdline, unsigned long addr, unsigned long size)
> +{
> +	int cmdlen, len;
> +	char str[50], *ptr;
> +
> +	addr = addr/1024;
> +	size = size/1024;
> +	ptr = str;
> +	strcpy (str, " mem=");
> +	ptr += strlen(str);
> +	ultoa(size, ptr);
> +	strcat (str, "K@");
> +	ptr = str + strlen(str);
> +	ultoa(addr, ptr);
> +	strcat (str, "K");
> +	len = strlen(str);
> +	cmdlen = strlen(cmdline) + len;
> +	if (cmdlen > (COMMAND_LINE_SIZE - 1))
> +		die("Command line overflow\n");
> +	strcat(cmdline, str);
> +
> +	return 0;
> +}
> +
> +/* Adds the elfcorehdr= command line parameter to command line. */
> +static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
> +{
> +	int cmdlen, len, align = 1024;
> +	char str[30], *ptr;
> +
> +	/* Passing in elfcorehdr=xxxK format. Saves space required in cmdline.
> +	 * Ensure 1K alignment*/
> +	if (addr%align)
> +		return -1;
> +	addr = addr/align;
> +	ptr = str;
> +	strcpy(str, " elfcorehdr=");
> +	ptr += strlen(str);
> +	ultoa(addr, ptr);
> +	strcat(str, "K");
> +	len = strlen(str);
> +	cmdlen = strlen(cmdline) + len;
> +	if (cmdlen > (COMMAND_LINE_SIZE - 1))
> +		die("Command line overflow\n");
> +	strcat(cmdline, str);
> +	return 0;
> +}
> +
> +/* Adds the savemaxmem= command line parameter to command line. */
> +static int cmdline_add_savemaxmem(char *cmdline, unsigned long long addr)
> +{
> +	int cmdlen, len, align = 1024;
> +	char str[30], *ptr;
> +
> +	/* Passing in savemaxmem=xxxM format. Saves space required in cmdline.*/
> +	addr = addr/(align*align);
> +	ptr = str;
> +	strcpy(str, " savemaxmem=");
> +	ptr += strlen(str);
> +	ultoa(addr, ptr);
> +	strcat(str, "M");
> +	len = strlen(str);
> +	cmdlen = strlen(cmdline) + len;
> +	if (cmdlen > (COMMAND_LINE_SIZE - 1))
> +		die("Command line overflow\n");
> +	strcat(cmdline, str);
> +	return 0;
> +}
> +
> +#ifdef __mips64
> +static struct crash_elf_info elf_info64 =
> +{
> +	class: ELFCLASS64,
> +	data: ELFDATA2MSB,
> +	machine: EM_MIPS,
> +	backup_src_start: BACKUP_SRC_START,
> +	backup_src_end: BACKUP_SRC_END,
> +	page_offset: PAGE_OFFSET,
> +	lowmem_limit: MAXMEM,
> +};
> +#endif
> +static struct crash_elf_info elf_info32 =
> +{
> +	class: ELFCLASS32,
> +	data: ELFDATA2MSB,
> +	machine: EM_MIPS,
> +	backup_src_start: BACKUP_SRC_START,
> +	backup_src_end: BACKUP_SRC_END,
> +	page_offset: PAGE_OFFSET,
> +	lowmem_limit: MAXMEM,
> +};
> +
> +/* Loads additional segments in case of a panic kernel is being loaded.
> + * One segment for backup region, another segment for storing elf headers
> + * for crash memory image.
> + */
> +int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
> +				unsigned long max_addr, unsigned long min_base)

Could you please mark unused parameters using UNUSED() ?

#include "unused.h"

...

int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
				unsigned long UNUSED(max_addr),
				unsigned long UNUSED(min_base))

> +{
> +	void *tmp;
> +	unsigned long sz, elfcorehdr;
> +	int nr_ranges, align = 1024;
> +	struct memory_range *mem_range;
> +
> +	if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
> +		return -1;
> +
> +	/* Create a backup region segment to store backup data*/
> +	sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
> +	tmp = xmalloc(sz);
> +	memset(tmp, 0, sz);
> +	info->backup_start = add_buffer(info, tmp, sz, sz, align,
> +				crash_reserved_mem.start,
> +				crash_reserved_mem.end,-1);	

The line above has a trailing white-space.

> +
> +#ifdef __mips64
> +	/* Create elf header segment and store crash image data. */
> +	if (arch_options.core_header_type == CORE_TYPE_ELF64) {
> +		if (crash_create_elf64_headers(info, &elf_info64,
> +					       crash_memory_range, nr_ranges,
> +					       &tmp, &sz,
> +					       ELF_CORE_HEADER_ALIGN) < 0)
> +			return -1;
> +	}
> +	else {
> +		if (crash_create_elf32_headers(info, &elf_info32,
> +					       crash_memory_range, nr_ranges,
> +					       &tmp, &sz,
> +					       ELF_CORE_HEADER_ALIGN) < 0)
> +			return -1;
> +	}
> +#else
> +	if (crash_create_elf32_headers(info, &elf_info32,
> +			       crash_memory_range, nr_ranges,
> +			       &tmp, &sz,
> +			       ELF_CORE_HEADER_ALIGN) < 0)
> +		return -1;
> +#endif
> +	elfcorehdr = add_buffer(info, tmp, sz, sz, align,
> +				crash_reserved_mem.start,
> +				crash_reserved_mem.end, -1);
> +
> +	/* 

The line above has a trailing white-space.

> +	 * backup segment is after elfcorehdr, so use elfcorehdr as top of
> +	 * kernel's available memory
> +	 */
> +	cmdline_add_mem(mod_cmdline, crash_reserved_mem.start,
> +		elfcorehdr - crash_reserved_mem.start);
> +	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
> +	cmdline_add_savemaxmem(mod_cmdline, saved_max_mem);
> +
> +#if 1
> +	printf("CRASH MEMORY RANGES:\n");
> +	printf("%016Lx-%016Lx\n", crash_reserved_mem.start, crash_reserved_mem.end);
> +#endif
> +
> +	

The line above has a trailing white-space.
Also, one blank line is probably enough here.

> +	return 0;
> +}
> +
> +int is_crashkernel_mem_reserved(void)
> +{
> +	uint64_t start, end;
> +
> +	return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ?
> +	  (start != end) : 0;
> +}
> +
> diff --git a/kexec/arch/mips/crashdump-mips.h b/kexec/arch/mips/crashdump-mips.h
> new file mode 100644
> index 0000000..4fb34c6
> --- /dev/null
> +++ b/kexec/arch/mips/crashdump-mips.h
> @@ -0,0 +1,26 @@
> +#ifndef CRASHDUMP_MIPS_H
> +#define CRASHDUMP_MIPS_H
> +
> +struct kexec_info;
> +int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
> +				unsigned long max_addr, unsigned long min_base);
> +#ifdef __mips64
> +#define PAGE_OFFSET	0xa800000000000000ULL
> +#else
> +#define PAGE_OFFSET	0x80000000
> +#endif
> +#define __pa(x)		((unsigned long)(X)& 0x7fffffff)
> +
> +#define MAXMEM		0x80000000
> +
> +#define CRASH_MAX_MEMMAP_NR	(KEXEC_MAX_SEGMENTS + 1)
> +#define CRASH_MAX_MEMORY_RANGES	(MAX_MEMORY_RANGES + 2)
> +
> +#define COMMAND_LINE_SIZE	512 

The line above has a trailing white-space.

> +
> +/* Backup Region, First 1M of System RAM. */
> +#define BACKUP_SRC_START	0x00000000
> +#define BACKUP_SRC_END		0x000fffff
> +#define BACKUP_SRC_SIZE	(BACKUP_SRC_END - BACKUP_SRC_START + 1)
> +
> +#endif /* CRASHDUMP_MIPS_H */
> diff --git a/kexec/arch/mips/kexec-elf-mips.c b/kexec/arch/mips/kexec-elf-mips.c
> index 95695b6..22ae21b 100644
> --- a/kexec/arch/mips/kexec-elf-mips.c
> +++ b/kexec/arch/mips/kexec-elf-mips.c
> @@ -25,55 +25,21 @@
>  #include <ip_checksum.h>
>  #include "../../kexec.h"
>  #include "../../kexec-elf.h"
> +#include "../../kexec-syscall.h"
>  #include "kexec-mips.h"
> +#include "crashdump-mips.h"
>  #include <arch/options.h>
>  
>  static const int probe_debug = 0;
>  
>  #define BOOTLOADER         "kexec"
>  #define MAX_COMMAND_LINE   256
> -
>  #define UPSZ(X) ((sizeof(X) + 3) & ~3)
> -static struct boot_notes {
> -	Elf_Bhdr hdr;
> -	Elf_Nhdr bl_hdr;
> -	unsigned char bl_desc[UPSZ(BOOTLOADER)];
> -	Elf_Nhdr blv_hdr;
> -	unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
> -	Elf_Nhdr cmd_hdr;
> -	unsigned char command_line[0];
> -} elf_boot_notes = {
> -	.hdr = {
> -		.b_signature = 0x0E1FB007,
> -		.b_size = sizeof(elf_boot_notes),
> -		.b_checksum = 0,
> -		.b_records = 3,
> -	},
> -	.bl_hdr = {
> -		.n_namesz = 0,
> -		.n_descsz = sizeof(BOOTLOADER),
> -		.n_type = EBN_BOOTLOADER_NAME,
> -	},
> -	.bl_desc = BOOTLOADER,
> -	.blv_hdr = {
> -		.n_namesz = 0,
> -		.n_descsz = sizeof(BOOTLOADER_VERSION),
> -		.n_type = EBN_BOOTLOADER_VERSION,
> -	},
> -	.blv_desc = BOOTLOADER_VERSION,
> -	.cmd_hdr = {
> -		.n_namesz = 0,
> -		.n_descsz = 0,
> -		.n_type = EBN_COMMAND_LINE,
> -	},
> -};
> -
> -
>  #define OPT_APPEND	(OPT_ARCH_MAX+0)
> +static char cmdline_buf[256] = "kexec ";
>  
>  int elf_mips_probe(const char *buf, off_t len)
>  {
> -
>  	struct mem_ehdr ehdr;
>  	int result;
>  	result = build_elf_exec_info(buf, len, &ehdr, 0);
> @@ -108,16 +74,14 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
>  	struct kexec_info *info)
>  {
>  	struct mem_ehdr ehdr;
> -	char *arg_buf;
> -	size_t arg_bytes;
> -	unsigned long arg_base;
> -	struct boot_notes *notes;
> -	size_t note_bytes;
>  	const char *command_line;
>  	int command_line_len;
> -	unsigned char *setup_start;
> -	uint32_t setup_size;
> +	char *crash_cmdline;

It looks like crash_cmdline needs to be initialised as NULL:

	char *crash_cmdline;

>  	int opt;
> +	int result;
> +	unsigned long cmdline_addr;
> +	int i;

This should be size_t i to avoid a signed/unsigned comparison further on.

> +	unsigned long bss_start, bss_size = 0;

Gcc complains that bss_start may be used uninitialised.
Bu the looks of things gcc is wrong. But could you initialise
bss_start to 0 anyway? I'm very enthusiastic about having
no compiler warnings these days.

>  	static const struct option options[] = {
>  		KEXEC_ARCH_OPTIONS
>  		{"command-line", 1, 0, OPT_APPEND},
> @@ -144,38 +108,85 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
>  			break;
>  		}
>  	}
> +
>  	command_line_len = 0;
> -	setup_simple_regs.spr9 = 0;
> -	if (command_line) {
> -		command_line_len = strlen(command_line) + 1;
> -		setup_simple_regs.spr9 = 2;
> +
> +	/* Need to append some command line parameters internally in case of
> +	 * taking crash dumps.
> +	 */
> +	if (info->kexec_flags & KEXEC_ON_CRASH) {
> +		crash_cmdline = xmalloc(COMMAND_LINE_SIZE);
> +		memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE);

		Hmm, perhaps we need xzalloc() or xcalloc().
		But thats not really your problem :-)

> +	}
> +
> +	result = build_elf_exec_info(buf, len, &ehdr, 0);
> +	if (result < 0) {
> +		die("ELF exec parse failed\n");
>  	}
>  
> -	/* Load the ELF executable */
> -	elf_exec_build_load(info, &ehdr, buf, len, 0);
> +	/* Read in the PT_LOAD segments and remove CKSEG0 mask from address*/
> +	for(i = 0; i < ehdr.e_phnum; i++) {
> +		struct mem_phdr *phdr;
> +		phdr = &ehdr.e_phdr[i];
> +		if (phdr->p_type == PT_LOAD) {
> +			phdr->p_paddr = virt_to_phys(phdr->p_paddr);
> +		}
> +	}
> +
> +	for(i = 0; i < ehdr.e_shnum; i++) {
> +		struct mem_shdr *shdr;
> +		unsigned char *strtab;
> +		strtab = (unsigned char *)ehdr.e_shdr[ehdr.e_shstrndx].sh_data;
> +
> +		shdr = &ehdr.e_shdr[i];
> +		if ( shdr->sh_size &&
> +				strcmp((char *)&strtab[shdr->sh_name],
> +					".bss") == 0) {
> +			bss_start = virt_to_phys(shdr->sh_addr);
> +			bss_size = shdr->sh_size;
> +			break;
> +		}
>  
> -	setup_start = setup_simple_start;
> -	setup_size = setup_simple_size;
> -	setup_simple_regs.spr8 = ehdr.e_entry;
> +	}
>  
> -	note_bytes = sizeof(elf_boot_notes) + ((command_line_len + 3) & ~3);
> -	arg_bytes = note_bytes + ((setup_size + 3) & ~3);
> +	/* Load the Elf data */
> +	result = elf_exec_load(&ehdr, info);
> +	if (result < 0) {
> +		die("ELF exec load failed\n");
> +	}
>  
> -	arg_buf = xmalloc(arg_bytes);
> -	arg_base = add_buffer_virt(info,
> -		 arg_buf, arg_bytes, arg_bytes, 4, 0, elf_max_addr(&ehdr), 1);
> +	info->entry = (void*)virt_to_phys(ehdr.e_entry);
> +	

The line above has tailing white-space.

> +	/* Put cmdline right after bss for crash*/
> +	if (info->kexec_flags & KEXEC_ON_CRASH)
> +		cmdline_addr = bss_start + bss_size;
> +	else
> +		cmdline_addr = 0;
>  
> -	notes = (struct boot_notes *)(arg_buf + ((setup_size + 3) & ~3));
> +	if(!bss_size)
> +		die("No .bss segment present\n");
>  
> -	memcpy(arg_buf, setup_start, setup_size);
> -	memcpy(notes, &elf_boot_notes, sizeof(elf_boot_notes));
> -	memcpy(notes->command_line, command_line, command_line_len);
> +	if (command_line)
> +		command_line_len = strlen(command_line) + 1;
>  
> -	notes->hdr.b_size = note_bytes;
> -	notes->cmd_hdr.n_descsz = command_line_len;
> -	notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
> +	if (info->kexec_flags & KEXEC_ON_CRASH) {
> +		result = load_crashdump_segments(info, crash_cmdline,
> +				0, 0);
> +		if (result < 0) {
> +			free(crash_cmdline);
> +			return -1;
> +		}
> +	}
>  
> -	info->entry = (void *)arg_base;
> +	if (command_line)
> +		strncat(cmdline_buf, command_line, command_line_len);
> +	if (crash_cmdline)
> +		strncat(cmdline_buf, crash_cmdline,
> +				sizeof(crash_cmdline) -
> +				strlen(crash_cmdline) - 1);
> +	add_buffer(info, cmdline_buf, sizeof(cmdline_buf),
> +			sizeof(cmdline_buf), sizeof(void*),
> +			cmdline_addr, 0x0fffffff, 1);
>  
>  	return 0;
>  }
> diff --git a/kexec/arch/mips/kexec-mips.c b/kexec/arch/mips/kexec-mips.c
> index cb75a2d..b3a24fa 100644
> --- a/kexec/arch/mips/kexec-mips.c
> +++ b/kexec/arch/mips/kexec-mips.c
> @@ -21,8 +21,6 @@
>  #include "kexec-mips.h"
>  #include <arch/options.h>
>  
> -#define MAX_MEMORY_RANGES  64
> -#define MAX_LINE          160
>  static struct memory_range memory_range[MAX_MEMORY_RANGES];
>  
>  /* Return a sorted list of memory ranges. */
> @@ -31,16 +29,6 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
>  {
>  	int memory_ranges = 0;
>  
> -#if 1
> -	/* this is valid for gemini2 platform based on tx4938
> -	 * in our case, /proc/iomem doesn't report ram space
> -	 */
> -	 memory_range[memory_ranges].start = 0x00000000;
> -	 memory_range[memory_ranges].end = 0x04000000;
> -	 memory_range[memory_ranges].type = RANGE_RAM;
> -	 memory_ranges++;
> -#else
> -#error Please, fix this for your platform
>  	const char iomem[] = "/proc/iomem";
>  	char line[MAX_LINE];
>  	FILE *fp;
> @@ -64,27 +52,20 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
>  #if 0
>  		printf("%016Lx-%016Lx : %s\n", start, end, str);
>  #endif

Please remove this debugging code or include it in a non-ifdefed-out manner.

> +		

The line above has trailing white-space.
:w

>  		if (memcmp(str, "System RAM\n", 11) == 0) {
>  			type = RANGE_RAM;
>  		} else if (memcmp(str, "reserved\n", 9) == 0) {
>  			type = RANGE_RESERVED;
> -		} else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
> -			type = RANGE_ACPI;
> -		} else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
> -			type = RANGE_ACPI_NVS;
>  		} else {
>  			continue;
>  		}
>  		memory_range[memory_ranges].start = start;
>  		memory_range[memory_ranges].end = end;
>  		memory_range[memory_ranges].type = type;
> -#if 0
> -		printf("%016Lx-%016Lx : %x\n", start, end, type);
> -#endif
>  		memory_ranges++;
>  	}
>  	fclose(fp);
> -#endif
>  
>  	*range = memory_range;
>  	*ranges = memory_ranges;
> @@ -98,8 +79,18 @@ int file_types = sizeof(file_type) / sizeof(file_type[0]);
>  
>  void arch_usage(void)
>  {
> +#ifdef __mips64
> +	fprintf(stderr, "     --elf32-core-headers Prepare core headers in "
> +			"ELF32 format\n");
> +#endif
>  }
>  
> +#ifdef __mips64
> +struct arch_options_t arch_options = {
> +	.core_header_type = CORE_TYPE_ELF64
> +};
> +#endif
> +
>  int arch_process_options(int argc, char **argv)
>  {
>  	static const struct option options[] = {
> @@ -126,12 +117,14 @@ const struct arch_map_entry arches[] = {
>  	/* For compatibility with older patches
>  	 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_MIPS here.
>  	 */
> -	{ "mips", KEXEC_ARCH_DEFAULT },
> +	{ "mips", KEXEC_ARCH_MIPS },
> +	{ "mips64", KEXEC_ARCH_MIPS },
>  	{ NULL, 0 },
>  };
>  
>  int arch_compat_trampoline(struct kexec_info *UNUSED(info))
>  {
> +
>  	return 0;
>  }
>  
> @@ -139,18 +132,9 @@ void arch_update_purgatory(struct kexec_info *UNUSED(info))
>  {
>  }
>  
> -/*
> - * Adding a dummy function, so that build on mips will not break.
> - * Need to implement the actual checking code
> - */
> -int is_crashkernel_mem_reserved(void)
> -{
> -	return 1;
> -}
> -
>  unsigned long virt_to_phys(unsigned long addr)
>  {
> -	return addr - 0x80000000;
> +	return addr & 0x7fffffff;
>  }
>  
>  /*
> @@ -159,7 +143,7 @@ unsigned long virt_to_phys(unsigned long addr)
>  void add_segment(struct kexec_info *info, const void *buf, size_t bufsz,
>  		 unsigned long base, size_t memsz)
>  {
> -	add_segment_phys_virt(info, buf, bufsz, base, memsz, 1);
> +	add_segment_phys_virt(info, buf, bufsz, virt_to_phys(base), memsz, 1);
>  }
>  
>  /*
> diff --git a/kexec/arch/mips/kexec-mips.h b/kexec/arch/mips/kexec-mips.h
> index 13f82be..8f72d06 100644
> --- a/kexec/arch/mips/kexec-mips.h
> +++ b/kexec/arch/mips/kexec-mips.h
> @@ -1,6 +1,11 @@
>  #ifndef KEXEC_MIPS_H
>  #define KEXEC_MIPS_H
>  
> +#define MAX_MEMORY_RANGES  64
> +#define MAX_LINE          160
> +
> +#define CORE_TYPE_ELF32 1
> +#define CORE_TYPE_ELF64 2
>  extern unsigned char setup_simple_start[];
>  extern uint32_t setup_simple_size;
>  
> @@ -14,4 +19,8 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
>  	struct kexec_info *info);
>  void elf_mips_usage(void);
>  
> +struct arch_options_t {
> +	        int      core_header_type;
> +};
> +
>  #endif /* KEXEC_MIPS_H */
> diff --git a/kexec/arch/mips/mips-setup-simple.S b/kexec/arch/mips/mips-setup-simple.S
> deleted file mode 100644
> index 1acdee3..0000000
> --- a/kexec/arch/mips/mips-setup-simple.S
> +++ /dev/null
> @@ -1,110 +0,0 @@
> -/*
> - * mips-setup-simple.S - code to execute before kernel to handle command line
> - * Copyright (C) 2007 Francesco Chiechi, Alessandro Rubini
> - * Copyright (C) 2007 Tvblob s.r.l.
> - *
> - * derived from Albert Herranz idea (ppc) adding command line support
> - * (boot_notes structure)
> - *
> - * This source code is licensed under the GNU General Public License,
> - * Version 2.  See the file COPYING for more details.
> - */
> -
> -/*
> - * Only suitable for platforms booting with MMU turned off.
> - * -- Albert Herranz
> - */
> -#include "regdef.h"
> -
> -/* returns  t0 = relocated address of sym */
> -/* modifies t1 t2 */
> -/* sym must not be global or this will not work (at least AFAIK up to now) */
> -#define RELOC_SYM(sym)                                                 \
> -	move    t0,ra;          /* save ra */                           \
> -	bal 1f;                                                         \
> -1:                                                                     \
> -	move    t1,ra;          /* now t1 is 1b (where we are now) */   \
> -	move    ra,t0;          /* restore ra */                        \
> -	lui     t2,%hi(1b);                                             \
> -	ori     t2,t2,%lo(1b);                                          \
> -	lui     t0,%hi(sym);                                            \
> -	ori     t0,t0,%lo(sym);                                         \
> -	sub     t0,t0,t2;       /* t0 = offset between sym and 1b */    \
> -	add     t0,t1,t0;       /* t0 = actual address in memory */
> -
> -	.data
> -	.globl setup_simple_start
> -setup_simple_start:
> -
> -	/* should perform here any required setup */
> -
> -	/* Initialize GOT pointer (verify if needed) */
> -	bal     1f
> -	nop
> -	.word   _GLOBAL_OFFSET_TABLE_
> -	1:
> -	move    gp, ra
> -	lw      t1, 0(ra)
> -	move    gp, t1
> -
> -	/* spr8 relocation */
> -	RELOC_SYM(spr8)
> -
> -	move    t4,t0           // save pointer to kernel start addr
> -	lw      t3,0(t0)        // save kernel start address
> -
> -	/* spr9 relocation */
> -	RELOC_SYM(spr9)
> -	lw      a0,0(t0)        // load argc
> -
> -	// this code is to be changed if boot_notes struct changes
> -	lw      t2,12(t4)       // t2 is size of boot_notes struct
> -	addi    t2,t2,3
> -	srl     t2,t2,2
> -	sll     v1,t2,2         // v1 = size of boot_notes struct
> -				// aligned to word boundary
> -
> -	addi    t0,t4,0x20      // t0 contains the address of "kexec" string
> -	add     v0,t4,v1        // v0 points to last word of boot_notes
> -	addi    v0,v0,8         // v0 points to address after boot_notes
> -	sw      t0,0(v0)        // store pointer to "kexec" string there
> -
> -	lw      t2,-8(t0)       // t2 is size of "kexec" string in bytes
> -	addi    t2,t2,3
> -	srl     t2,t2,2
> -	sll     v1,t2,2         // v1 = size of "kexec" string
> -				// aligned to word boundary
> -	add     t2,t0,v1
> -	addi    t0,t2,4         // t0 points to size of version string
> -
> -	lw      t2,0(t0)        // t2 is size of version string in bytes
> -	addi    t2,t2,3
> -	srl     t2,t2,2
> -	sll     v1,t2,2         // v1 = size of version string
> -				// aligned to word boundary
> -
> -	addi    t0,t0,8         // t0 points to version string
> -	add     t0,t0,v1        // t0 points to start of command_line record
> -	addi    t0,t0,12        // t0 points command line
> -
> -	sw      t0,4(v0)        // store pointer to command line
> -
> -	move    a1,v0           // load argv
> -	li      a2,0
> -	li      a3,0
> -
> -	jr      t3
> -	nop
> -
> -	.balign 4
> -	.globl setup_simple_regs
> -setup_simple_regs:
> -spr8:	.long 0x00000000
> -spr9:	.long 0x00000000
> -
> -setup_simple_end:
> -
> -	.globl setup_simple_size
> -setup_simple_size:
> -	.long setup_simple_end - setup_simple_start
> -
> diff --git a/kexec/crashdump.h b/kexec/crashdump.h
> index 1789b53..30d6f29 100644
> --- a/kexec/crashdump.h
> +++ b/kexec/crashdump.h
> @@ -26,7 +26,7 @@ struct crash_elf_info {
>  	unsigned long backup_src_start;
>  	unsigned long backup_src_end;
>  
> -	unsigned long page_offset;
> +	unsigned long long page_offset;
>  	unsigned long lowmem_limit;
>  
>  	int (*get_note_info)(int cpu, uint64_t *addr, uint64_t *len);
> diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h
> index 69c9686..7f41a1b 100644
> --- a/kexec/kexec-syscall.h
> +++ b/kexec/kexec-syscall.h
> @@ -22,6 +22,7 @@
>  #define LINUX_REBOOT_CMD_KEXEC_OLD2	0x18263645
>  #define LINUX_REBOOT_CMD_KEXEC		0x45584543
>  
> +#ifndef __NR_kexec_load
>  #ifdef __i386__
>  #define __NR_kexec_load		283
>  #endif
> @@ -60,6 +61,7 @@
>  #ifndef __NR_kexec_load
>  #error Unknown processor architecture.  Needs a kexec_load syscall number.
>  #endif
> +#endif /*ifndef __NR_kexec_load*/
>  
>  struct kexec_segment;
>  
> 
> 
> Signed-off-by: Maxim Uvarov <muvarov at gmail.com>

Please put the Signed-off-by line above the patch,
after the description for the patch :-)



More information about the kexec mailing list