diff options
author | Per Fransson <per.xx.fransson@stericsson.com> | 2011-09-16 15:36:38 +0200 |
---|---|---|
committer | Preetham-rao K <preetham.rao@stericsson.com> | 2011-10-04 11:20:09 +0200 |
commit | 63078acfbcc0362422df62d13553cba7bd2b9f08 (patch) | |
tree | 554e236cf4b4448c02306304f0f0862543fa7deb | |
parent | abdfc6de651588ffa6f415ec198e7dc7a5be02e7 (diff) |
u8500: Create dump ELF based on 'memargs'
If there is no elfcorehdr available when dumping, create one based on
the memargs environment variable.
ST-Ericsson ID: 340331
ST-Ericsson FOSS-OUT ID: NA
Change-Id: Ia5a2ecd427d98e61010f13c68bc8056c81f7d76f
Signed-off-by: Per Fransson <per.xx.fransson@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32692
Reviewed-by: QATOOLS
Reviewed-by: Wenhai FANG <wenhai.h.fang@stericsson.com>
Reviewed-by: Preetham-rao K <preetham.rao@stericsson.com>
-rw-r--r-- | board/st-ericsson/u8500/cmd_cdump.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/board/st-ericsson/u8500/cmd_cdump.c b/board/st-ericsson/u8500/cmd_cdump.c index 757ed938e..645a554e9 100644 --- a/board/st-ericsson/u8500/cmd_cdump.c +++ b/board/st-ericsson/u8500/cmd_cdump.c @@ -11,6 +11,9 @@ #include <common.h> #include <command.h> +#ifdef CONFIG_SYS_HUSH_PARSER +#include <hush.h> +#endif #include "malloc.h" #include <mmc.h> #include <asm/io.h> @@ -20,6 +23,7 @@ #include <fat.h> #include <asm/arch/hardware.h> #include <exports.h> +#include <linux/ctype.h> #define TWD_WDOG_LOAD 0x20 #define TWD_WDOG_CONTROL 0x28 @@ -393,6 +397,286 @@ static int reboot_at_crash(void) return 1; } +typedef struct range { + unsigned long start; + unsigned long size; +} range_t; + +/* + * Parse nn[KMG]@ss[KMG] + */ +static void suffixed_addr_toul(char *s, range_t *r) +{ + char *end_ptr; + unsigned long suffix_mult; + + r->size = simple_strtoul(s, &end_ptr, 0); + suffix_mult = 1; + switch (*end_ptr) { + case 'G': + suffix_mult *= 1024; + case 'M': + suffix_mult *= 1024; + case 'K': + suffix_mult *= 1024; + end_ptr++; + break; + } + r->size *= suffix_mult; + + if (*end_ptr != '@') { + r->start = 0; + return; + } + + s = end_ptr + 1; + r->start = simple_strtoul(s, &end_ptr, 0); + suffix_mult = 1; + switch (*end_ptr) { + case 'G': + suffix_mult *= 1024; + case 'M': + suffix_mult *= 1024; + case 'K': + suffix_mult *= 1024; + end_ptr++; + break; + } + r->start *= suffix_mult; + return; +} + +Elf32_Ehdr *create_elfhdr(range_t *regions, unsigned int region_no) { + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + unsigned int hdr_size; + unsigned int i; + + hdr_size = sizeof(*ehdr)+(region_no+1)*sizeof(*phdr); + ehdr = memset(malloc(hdr_size), 0, hdr_size); + if(ehdr == NULL) { + return NULL; + } + + ehdr->e_ident[EI_MAG0] = ELFMAG0; + ehdr->e_ident[EI_MAG1] = ELFMAG1; + ehdr->e_ident[EI_MAG2] = ELFMAG2; + ehdr->e_ident[EI_MAG3] = ELFMAG3; + ehdr->e_ident[EI_CLASS] = ELFCLASS32; + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; + ehdr->e_ident[EI_VERSION] = 1; + ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr->e_ident[EI_ABIVERSION] = ELFABIVERSION; + ehdr->e_type = ET_CORE; + ehdr->e_machine = EM_ARM; + ehdr->e_version = EV_CURRENT; + ehdr->e_entry = 0x0; + ehdr->e_phoff = sizeof(*ehdr); + ehdr->e_shoff = 0x0; + ehdr->e_flags = 0x0; + ehdr->e_ehsize = sizeof(*ehdr); + ehdr->e_phentsize = sizeof(*phdr); + ehdr->e_phnum = region_no+1; + ehdr->e_shentsize = 0; + ehdr->e_shnum = 0; + ehdr->e_shstrndx = 0; + + phdr = (Elf32_Phdr*)(ehdr + 1); + phdr[0].p_type = PT_NOTE; + + for (i=0; i<region_no; i++) { + phdr[i+1].p_type = PT_LOAD; + phdr[i+1].p_vaddr = 0xc0000000 + regions[i].start; + phdr[i+1].p_paddr = regions[i].start; + phdr[i+1].p_filesz = regions[i].size; + phdr[i+1].p_memsz = regions[i].size; + phdr[i+1].p_flags = PF_X | PF_W | PF_R; + } + return ehdr; +} + +int dump_regions_from_environment(void) +{ + Elf32_Ehdr *elfhdr_addr; + int rc = 0; + char *orig_bootargs; + char *bootargs; + char *p; + char *memargs_cmd; + char *memargs; + int nuf_ph; + range_t ck = {0, 0}; + range_t *regions; + char *crashkernel; + unsigned int i; + unsigned int region_no; + + /* + Right now getenv("crashkernel") has a value on the form + "crashkernel=nn[KMG]@ss[KMG]" + but this is expanded into + "crashkernel=${crashkernel}" + when constructing the kernel commandline, amounting to: + "crashkernel=crashkernel=nn[KMG]@ss[KMG]" + This might get fixed so this code can handle both. + */ + crashkernel = getenv("crashkernel"); + if(crashkernel == NULL) { + debug("checkcrash: no crashkernel environment variable\n"); + rc = 1; + goto out5; + } + crashkernel = strdup(crashkernel); + if(crashkernel == NULL) { + debug("checkcrash: could not strdup crashkernel variable\n"); + rc = 1; + goto out5; + } + p = strchr(crashkernel, '='); + if (p != NULL) { + p++; + suffixed_addr_toul(p, &ck); + } + else { + suffixed_addr_toul(crashkernel, &ck); + } + + /* Make copy of bootargs, if it exists */ + orig_bootargs = getenv("bootargs"); + if(orig_bootargs != NULL) { + orig_bootargs = strdup(orig_bootargs); + if(orig_bootargs == NULL) { + debug("checkcrash: could not strdup bootargs variable to reset to\n"); + rc = 1; + goto out4; + } + } + + /* Unset bootargs */ + if (setenv("bootargs", "") != 0) { + debug("checkcrash: could not unset bootargs variable\n"); + rc = 1; + goto out3; + } + + /* Run memargs to set bootargs */ + memargs_cmd = getenv("memargs"); + if(memargs_cmd == NULL) { + debug("checkcrash: no memargs_cmd environment variable\n"); + rc = 1; + goto out3; + } + +#ifndef CONFIG_SYS_HUSH_PARSER + if (run_command(memargs_cmd, 0) < 0) { + debug("checkcrash: failed to run memargs\n"); + rc = 1; + goto out3; + } +#else + if (parse_string_outer(memargs_cmd, + FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0) { + debug("checkcrash: failed to run memargs\n"); + rc = 1; + goto out3; + } +#endif + + memargs = bootargs = strdup(getenv("bootargs")); + if(bootargs == NULL) { + debug("checkcrash: could not strdup bootargs variable to manipulate it\n"); + rc = 1; + goto out3; + } + + /* Restore bootargs */ + if (orig_bootargs && setenv("bootargs", orig_bootargs)) { + debug("checkcrash: could not reset bootargs variable\n"); + rc = 1; + goto out2; + } + + /* Calculate the number of regions */ + nuf_ph = 1; // One extra since the crashkernel is likely to split one of the regions + p = memargs; + while (*p != '\0') { + if (strncmp(p, "mem=", 4)==0) {nuf_ph++;} + while (!isspace(*p)) { + p++; + } + while (isspace(*p)) { + p++; + } + } + regions = malloc(nuf_ph*sizeof(*regions)); + if (regions == NULL) { + debug("checkcrash: could not allocate array of ranges\n"); + rc = 1; + goto out2; + } + + region_no = 0; + while (memargs != NULL) { + p = strsep(&memargs, " \t"); + if (strncmp(p, "mem=", 4)!=0) { + continue; + } + p += 4; + suffixed_addr_toul(p, ®ions[region_no]); + if (ck.start==(regions[region_no].start) && + (ck.start+ck.size)==(regions[region_no].start+regions[region_no].size)) { + /* Skip */ + } + else if (ck.start==(regions[region_no].start) && + (ck.start+ck.size)<(regions[region_no].start+regions[region_no].size)) { + /* Skip beginning */ + regions[region_no].start = ck.start+ck.size; + regions[region_no].size -= ck.size; + } + else if (ck.start>(regions[region_no].start) && + (ck.start+ck.size)==(regions[region_no].start+regions[region_no].size)) { + /* Skip end */ + regions[region_no].size -= ck.size; + } + else if (ck.start>=(regions[region_no].start) && + (ck.start+ck.size)<=(regions[region_no].start+regions[region_no].size)) { + /* Split */ + regions[region_no+1].start = ck.start + ck.size; + regions[region_no+1].size = (regions[region_no].start + regions[region_no].size) - + regions[region_no+1].start; + regions[region_no].size = ck.start - regions[region_no].start; + region_no++; + } + region_no++; + } + + for (i=0;i<region_no;i++) { + debug("%lu placed at %lu\n", regions[i].size, regions[i].start); + } + + elfhdr_addr = create_elfhdr(regions, region_no); + if (elfhdr_addr == NULL) { + debug("Could not create elfhdr\n"); + rc = 1; + goto out1; + } + + if (crashdump(elfhdr_addr, crash_filename) != 0) { + rc = 1; + } + +out1: + free(regions); +out2: + free(bootargs); +out3: + free(orig_bootargs); +out4: + free(crashkernel); +out5: + return rc; +} + /* * Dump crash to file (typically FAT file on SD/MMC). */ @@ -417,6 +701,11 @@ static int do_checkcrash(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) "error writing dump from %x to %s\n", (u32) elfhdr_addr, crash_filename); } + else { + printf("crash dump elf header not found. Will try to create one" + " Dumping to card...\n"); + rc = dump_regions_from_environment(); + } } stop_mpcore_wdt(); |