aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPer Fransson <per.xx.fransson@stericsson.com>2011-09-16 15:36:38 +0200
committerPreetham-rao K <preetham.rao@stericsson.com>2011-10-04 11:20:09 +0200
commit63078acfbcc0362422df62d13553cba7bd2b9f08 (patch)
tree554e236cf4b4448c02306304f0f0862543fa7deb
parentabdfc6de651588ffa6f415ec198e7dc7a5be02e7 (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.c289
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, &regions[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();