[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