diff options
author | wdenk <wdenk> | 2002-11-03 00:01:44 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2002-11-03 00:01:44 +0000 |
commit | 47d1a6e1ed87fe1fb3d737acdb85f69bc3259522 (patch) | |
tree | bcf85bebad1b0b31392a84a649595beacaa57ab1 /common/cmd_bootm.c | |
parent | e221174377d7e3ee848e014b96430d4c97023e93 (diff) | |
download | u-boot-imx-47d1a6e1ed87fe1fb3d737acdb85f69bc3259522.zip u-boot-imx-47d1a6e1ed87fe1fb3d737acdb85f69bc3259522.tar.gz u-boot-imx-47d1a6e1ed87fe1fb3d737acdb85f69bc3259522.tar.bz2 |
Initial revision
Diffstat (limited to 'common/cmd_bootm.c')
-rw-r--r-- | common/cmd_bootm.c | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c new file mode 100644 index 0000000..e8ce40d --- /dev/null +++ b/common/cmd_bootm.c @@ -0,0 +1,931 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Boot support + */ +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <cmd_boot.h> +#include <image.h> +#include <malloc.h> +#include <zlib.h> +#include <asm/byteorder.h> +#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP) +#include <rtc.h> +#endif + +#ifdef CFG_HUSH_PARSER +#include <hush.h> +#endif + +#ifdef CONFIG_SHOW_BOOT_PROGRESS +# include <status_led.h> +# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg) +#else +# define SHOW_BOOT_PROGRESS(arg) +#endif + +#ifdef CFG_INIT_RAM_LOCK +#include <asm/cache.h> +#endif + +/* + * Some systems (for example LWMON) have very short watchdog periods; + * we must make sure to split long operations like memmove() or + * crc32() into reasonable chunks. + */ +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +# define CHUNKSZ (64 * 1024) +#endif + +int gunzip (void *, int, unsigned char *, int *); + +static void *zalloc(void *, unsigned, unsigned); +static void zfree(void *, void *, unsigned); + +#if (CONFIG_COMMANDS & CFG_CMD_IMI) +static int image_info (unsigned long addr); +#endif +static void print_type (image_header_t *hdr); + +/* + * Continue booting an OS image; caller already has: + * - copied image header to global variable `header' + * - checked header magic number, checksums (both header & image), + * - verified image architecture (PPC) and type (KERNEL or MULTI), + * - loaded (first part of) image to header load address, + * - disabled interrupts. + */ +typedef void boot_os_Fcn (cmd_tbl_t *cmdtp, int flag, + int argc, char *argv[], + ulong addr, /* of image to boot */ + ulong *len_ptr, /* multi-file image length table */ + int verify); /* getenv("verify")[0] != 'n' */ + +#ifndef CONFIG_ARM +static boot_os_Fcn do_bootm_linux; +#else +extern boot_os_Fcn do_bootm_linux; +#endif +static boot_os_Fcn do_bootm_netbsd; +#if (CONFIG_COMMANDS & CFG_CMD_ELF) +static boot_os_Fcn do_bootm_vxworks; +static boot_os_Fcn do_bootm_qnxelf; +int do_bootvx ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] ); +int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] ); +#endif /* CFG_CMD_ELF */ + +image_header_t header; + +ulong load_addr = CFG_LOAD_ADDR; /* Default Load Address */ + +int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong iflag; + ulong addr; + ulong data, len, checksum; + ulong *len_ptr; + int i, verify; + char *name, *s; + int (*appl)(cmd_tbl_t *, int, int, char *[]); + image_header_t *hdr = &header; + + s = getenv ("verify"); + verify = (s && (*s == 'n')) ? 0 : 1; + + if (argc < 2) { + addr = load_addr; + } else { + addr = simple_strtoul(argv[1], NULL, 16); + } + + SHOW_BOOT_PROGRESS (1); + printf ("## Booting image at %08lx ...\n", addr); + + /* Copy header so we can blank CRC field for re-calculation */ + memmove (&header, (char *)addr, sizeof(image_header_t)); + + if (ntohl(hdr->ih_magic) != IH_MAGIC) { + printf ("Bad Magic Number\n"); + SHOW_BOOT_PROGRESS (-1); + return 1; + } + SHOW_BOOT_PROGRESS (2); + + data = (ulong)&header; + len = sizeof(image_header_t); + + checksum = ntohl(hdr->ih_hcrc); + hdr->ih_hcrc = 0; + + if (crc32 (0, (char *)data, len) != checksum) { + printf ("Bad Header Checksum\n"); + SHOW_BOOT_PROGRESS (-2); + return 1; + } + SHOW_BOOT_PROGRESS (3); + + /* for multi-file images we need the data part, too */ + print_image_hdr ((image_header_t *)addr); + + data = addr + sizeof(image_header_t); + len = ntohl(hdr->ih_size); + + if (verify) { + printf (" Verifying Checksum ... "); + if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) { + printf ("Bad Data CRC\n"); + SHOW_BOOT_PROGRESS (-3); + return 1; + } + printf ("OK\n"); + } + SHOW_BOOT_PROGRESS (4); + + len_ptr = (ulong *)data; + + if (hdr->ih_arch != IH_CPU_PPC && hdr->ih_arch != IH_CPU_ARM) { + printf ("Unsupported Architecture\n"); + SHOW_BOOT_PROGRESS (-4); + return 1; + } + SHOW_BOOT_PROGRESS (5); + + switch (hdr->ih_type) { + case IH_TYPE_STANDALONE: name = "Standalone Application"; + break; + case IH_TYPE_KERNEL: name = "Kernel Image"; + break; + case IH_TYPE_MULTI: name = "Multi-File Image"; + len = ntohl(len_ptr[0]); + /* OS kernel is always the first image */ + data += 8; /* kernel_len + terminator */ + for (i=1; len_ptr[i]; ++i) + data += 4; + break; + default: printf ("Wrong Image Type for %s command\n", cmdtp->name); + SHOW_BOOT_PROGRESS (-5); + return 1; + } + SHOW_BOOT_PROGRESS (6); + + /* + * We have reached the point of no return: we are going to + * overwrite all exception vector code, so we cannot easily + * recover from any failures any more... + */ + + iflag = disable_interrupts(); + + switch (hdr->ih_comp) { + case IH_COMP_NONE: + if(hdr->ih_load == addr) { + printf (" XIP %s ... ", name); + } else { +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + size_t l = len; + void *to = (void *)ntohl(hdr->ih_load); + void *from = (void *)data; + + printf (" Loading %s ... ", name); + + while (l > 0) { + size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; + WATCHDOG_RESET(); + memmove (to, from, tail); + to += tail; + from += tail; + l -= tail; + } +#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ + memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); +#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ + } + break; + case IH_COMP_GZIP: + printf (" Uncompressing %s ... ", name); + if (gunzip ((void *)ntohl(hdr->ih_load), 0x400000, + (uchar *)data, (int *)&len) != 0) { + printf ("GUNZIP ERROR - must RESET board to recover\n"); + SHOW_BOOT_PROGRESS (-6); + do_reset (cmdtp, flag, argc, argv); + } + break; + default: + if (iflag) + enable_interrupts(); + printf ("Unimplemented compression type %d\n", hdr->ih_comp); + SHOW_BOOT_PROGRESS (-7); + return 1; + } + printf ("OK\n"); + SHOW_BOOT_PROGRESS (7); + + switch (hdr->ih_type) { + case IH_TYPE_STANDALONE: + appl = (int (*)(cmd_tbl_t *, int, int, char *[]))ntohl(hdr->ih_ep); + if (iflag) + enable_interrupts(); + + (*appl)(cmdtp, flag, argc-1, &argv[1]); + break; + case IH_TYPE_KERNEL: + case IH_TYPE_MULTI: + /* handled below */ + break; + default: + if (iflag) + enable_interrupts(); + printf ("Can't boot image type %d\n", hdr->ih_type); + SHOW_BOOT_PROGRESS (-8); + return 1; + } + SHOW_BOOT_PROGRESS (8); + + switch (hdr->ih_os) { + default: /* handled by (original) Linux case */ + case IH_OS_LINUX: + do_bootm_linux (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; + case IH_OS_NETBSD: + do_bootm_netbsd (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; +#if (CONFIG_COMMANDS & CFG_CMD_ELF) + case IH_OS_VXWORKS: + do_bootm_vxworks (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; + case IH_OS_QNX: + do_bootm_qnxelf (cmdtp, flag, argc, argv, + addr, len_ptr, verify); + break; +#endif /* CFG_CMD_ELF */ + } + + SHOW_BOOT_PROGRESS (-9); +#ifdef DEBUG + printf ("\n## Control returned to monitor - resetting...\n"); + do_reset (cmdtp, flag, argc, argv); +#endif + return 1; +} + +#ifndef CONFIG_ARM +static void +do_bootm_linux (cmd_tbl_t *cmdtp, int flag, + int argc, char *argv[], + ulong addr, + ulong *len_ptr, + int verify) +{ + DECLARE_GLOBAL_DATA_PTR; + + ulong sp; + ulong len, checksum; + ulong initrd_start, initrd_end; + ulong cmd_start, cmd_end; + ulong initrd_high; + ulong data; + char *cmdline; + char *s; + bd_t *kbd; + void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); + image_header_t *hdr = &header; + + if ((s = getenv ("initrd_high")) != NULL) { + /* a value of "no" or a similar string will act like 0, + * turning the "load high" feature off. This is intentional. + */ + initrd_high = simple_strtoul(s, NULL, 16); + } else { /* not set, no restrictions to load high */ + initrd_high = ~0; + } + + /* + * Booting a (Linux) kernel image + * + * Allocate space for command line and board info - the + * address should be as high as possible within the reach of + * the kernel (see CFG_BOOTMAPSZ settings), but in unused + * memory, which means far enough below the current stack + * pointer. + */ + + asm( "mr %0,1": "=r"(sp) : ); + +#ifdef DEBUG + printf ("## Current stack ends at 0x%08lX ", sp); +#endif + sp -= 2048; /* just to be sure */ + if (sp > CFG_BOOTMAPSZ) + sp = CFG_BOOTMAPSZ; + sp &= ~0xF; + +#ifdef DEBUG + printf ("=> set upper limit to 0x%08lX\n", sp); +#endif + cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF); + kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF); + + if ((s = getenv("bootargs")) == NULL) + s = ""; + + strcpy (cmdline, s); + + cmd_start = (ulong)&cmdline[0]; + cmd_end = cmd_start + strlen(cmdline); + + *kbd = *(gd->bd); + +#ifdef DEBUG + printf ("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end); + + do_bdinfo (NULL, 0, 0, NULL); +#endif + + if ((s = getenv ("clocks_in_mhz")) != NULL) { + /* convert all clock information to MHz */ + kbd->bi_intfreq /= 1000000L; + kbd->bi_busfreq /= 1000000L; +#if defined(CONFIG_8260) + kbd->bi_cpmfreq /= 1000000L; + kbd->bi_brgfreq /= 1000000L; + kbd->bi_sccfreq /= 1000000L; + kbd->bi_vco /= 1000000L; +#endif /* CONFIG_8260 */ + } + + kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep; + + /* + * Check if there is an initrd image + */ + if (argc >= 3) { + SHOW_BOOT_PROGRESS (9); + + addr = simple_strtoul(argv[2], NULL, 16); + + printf ("## Loading RAMDisk Image at %08lx ...\n", addr); + + /* Copy header so we can blank CRC field for re-calculation */ + memmove (&header, (char *)addr, sizeof(image_header_t)); + + if (hdr->ih_magic != IH_MAGIC) { + printf ("Bad Magic Number\n"); + SHOW_BOOT_PROGRESS (-10); + do_reset (cmdtp, flag, argc, argv); + } + + data = (ulong)&header; + len = sizeof(image_header_t); + + checksum = hdr->ih_hcrc; + hdr->ih_hcrc = 0; + + if (crc32 (0, (char *)data, len) != checksum) { + printf ("Bad Header Checksum\n"); + SHOW_BOOT_PROGRESS (-11); + do_reset (cmdtp, flag, argc, argv); + } + + SHOW_BOOT_PROGRESS (10); + + print_image_hdr (hdr); + + data = addr + sizeof(image_header_t); + len = hdr->ih_size; + + if (verify) { + ulong csum = 0; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + ulong cdata = data, edata = cdata + len; +#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ + + printf (" Verifying Checksum ... "); + +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + + while (cdata < edata) { + ulong chunk = edata - cdata; + + if (chunk > CHUNKSZ) + chunk = CHUNKSZ; + csum = crc32 (csum, (char *)cdata, chunk); + cdata += chunk; + + WATCHDOG_RESET(); + } +#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ + csum = crc32 (0, (char *)data, len); +#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ + + if (csum != hdr->ih_dcrc) { + printf ("Bad Data CRC\n"); + SHOW_BOOT_PROGRESS (-12); + do_reset (cmdtp, flag, argc, argv); + } + printf ("OK\n"); + } + + SHOW_BOOT_PROGRESS (11); + + if ((hdr->ih_os != IH_OS_LINUX) || + (hdr->ih_arch != IH_CPU_PPC) || + (hdr->ih_type != IH_TYPE_RAMDISK) ) { + printf ("No Linux PPC Ramdisk Image\n"); + SHOW_BOOT_PROGRESS (-13); + do_reset (cmdtp, flag, argc, argv); + } + + /* + * Now check if we have a multifile image + */ + } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) { + u_long tail = ntohl(len_ptr[0]) % 4; + int i; + + SHOW_BOOT_PROGRESS (13); + + /* skip kernel length and terminator */ + data = (ulong)(&len_ptr[2]); + /* skip any additional image length fields */ + for (i=1; len_ptr[i]; ++i) + data += 4; + /* add kernel length, and align */ + data += ntohl(len_ptr[0]); + if (tail) { + data += 4 - tail; + } + + len = ntohl(len_ptr[1]); + + } else { + /* + * no initrd image + */ + SHOW_BOOT_PROGRESS (14); + + len = data = 0; + } + +#ifdef DEBUG + if (!data) { + printf ("No initrd\n"); + } +#endif + + if (data) { + initrd_start = (ulong)kbd - len; + initrd_start &= ~(4096 - 1); /* align on page */ + + if (initrd_high) { + ulong nsp; + + /* + * the inital ramdisk does not need to be within + * CFG_BOOTMAPSZ as it is not accessed until after + * the mm system is initialised. + * + * do the stack bottom calculation again and see if + * the initrd will fit just below the monitor stack + * bottom without overwriting the area allocated + * above for command line args and board info. + */ + asm( "mr %0,1": "=r"(nsp) : ); + nsp -= 2048; /* just to be sure */ + nsp &= ~0xF; + if (nsp > initrd_high) /* limit as specified */ + nsp = initrd_high; + nsp -= len; + nsp &= ~(4096 - 1); /* align on page */ + if (nsp >= sp) + initrd_start = nsp; + } + + SHOW_BOOT_PROGRESS (12); +#ifdef DEBUG + printf ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n", + data, data + len - 1, len, len); +#endif + initrd_end = initrd_start + len; + printf (" Loading Ramdisk to %08lx, end %08lx ... ", + initrd_start, initrd_end); +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + { + size_t l = len; + void *to = (void *)initrd_start; + void *from = (void *)data; + + while (l > 0) { + size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; + WATCHDOG_RESET(); + memmove (to, from, tail); + to += tail; + from += tail; + l -= tail; + } + } +#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ + memmove ((void *)initrd_start, (void *)data, len); +#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ + printf ("OK\n"); + } else { + initrd_start = 0; + initrd_end = 0; + } + +#ifdef DEBUG + printf ("## Transferring control to Linux (at address %08lx) ...\n", + (ulong)kernel); +#endif + SHOW_BOOT_PROGRESS (15); + +#ifdef CFG_INIT_RAM_LOCK + unlock_ram_in_cache(); +#endif + /* + * Linux Kernel Parameters: + * r3: ptr to board info data + * r4: initrd_start or 0 if no initrd + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + */ + (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); +} +#endif /* CONFIG_ARM */ + +static void +do_bootm_netbsd (cmd_tbl_t *cmdtp, int flag, + int argc, char *argv[], + ulong addr, + ulong *len_ptr, + int verify) +{ + DECLARE_GLOBAL_DATA_PTR; + + image_header_t *hdr = &header; + + void (*loader)(bd_t *, image_header_t *, char *, char *); + image_header_t *img_addr; + char *consdev; + char *cmdline; + + + /* + * Booting a (NetBSD) kernel image + * + * This process is pretty similar to a standalone application: + * The (first part of an multi-) image must be a stage-2 loader, + * which in turn is responsible for loading & invoking the actual + * kernel. The only differences are the parameters being passed: + * besides the board info strucure, the loader expects a command + * line, the name of the console device, and (optionally) the + * address of the original image header. + */ + + img_addr = 0; + if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) + img_addr = (image_header_t *) addr; + + + consdev = ""; +#if defined (CONFIG_8xx_CONS_SMC1) + consdev = "smc1"; +#elif defined (CONFIG_8xx_CONS_SMC2) + consdev = "smc2"; +#elif defined (CONFIG_8xx_CONS_SCC2) + consdev = "scc2"; +#elif defined (CONFIG_8xx_CONS_SCC3) + consdev = "scc3"; +#endif + + if (argc > 2) { + ulong len; + int i; + + for (i=2, len=0 ; i<argc ; i+=1) + len += strlen (argv[i]) + 1; + cmdline = malloc (len); + + for (i=2, len=0 ; i<argc ; i+=1) { + if (i > 2) + cmdline[len++] = ' '; + strcpy (&cmdline[len], argv[i]); + len += strlen (argv[i]); + } + } else if ((cmdline = getenv("bootargs")) == NULL) { + cmdline = ""; + } + + loader = (void (*)(bd_t *, image_header_t *, char *, char *)) hdr->ih_ep; + + printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n", + (ulong)loader); + + SHOW_BOOT_PROGRESS (15); + + /* + * NetBSD Stage-2 Loader Parameters: + * r3: ptr to board info data + * r4: image address + * r5: console device + * r6: boot args string + */ + (*loader) (gd->bd, img_addr, consdev, cmdline); +} + +#if (CONFIG_COMMANDS & CFG_CMD_BOOTD) +int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int rcode = 0; +#ifndef CFG_HUSH_PARSER + if (run_command (getenv ("bootcmd"), flag) < 0) rcode = 1; +#else + if (parse_string_outer(getenv("bootcmd"), + FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0 ) rcode = 1; +#endif + return rcode; +} +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_IMI) +int do_iminfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int arg; + ulong addr; + int rcode=0; + + if (argc < 2) { + return image_info (load_addr); + } + + for (arg=1; arg <argc; ++arg) { + addr = simple_strtoul(argv[arg], NULL, 16); + if (image_info (addr) != 0) rcode = 1; + } + return rcode; +} + +static int image_info (ulong addr) +{ + ulong data, len, checksum; + image_header_t *hdr = &header; + + printf ("\n## Checking Image at %08lx ...\n", addr); + + /* Copy header so we can blank CRC field for re-calculation */ + memmove (&header, (char *)addr, sizeof(image_header_t)); + + if (ntohl(hdr->ih_magic) != IH_MAGIC) { + printf (" Bad Magic Number\n"); + return 1; + } + + data = (ulong)&header; + len = sizeof(image_header_t); + + checksum = ntohl(hdr->ih_hcrc); + hdr->ih_hcrc = 0; + + if (crc32 (0, (char *)data, len) != checksum) { + printf (" Bad Header Checksum\n"); + return 1; + } + + /* for multi-file images we need the data part, too */ + print_image_hdr ((image_header_t *)addr); + + data = addr + sizeof(image_header_t); + len = ntohl(hdr->ih_size); + + printf (" Verifying Checksum ... "); + if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) { + printf (" Bad Data CRC\n"); + return 1; + } + printf ("OK\n"); + return 0; +} +#endif /* CFG_CMD_IMI */ + +void +print_image_hdr (image_header_t *hdr) +{ +#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP) + time_t timestamp = (time_t)ntohl(hdr->ih_time); + struct rtc_time tm; +#endif + + printf (" Image Name: %.*s\n", IH_NMLEN, hdr->ih_name); +#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP) + to_tm (timestamp, &tm); + printf (" Created: %4d-%02d-%02d %2d:%02d:%02d UTC\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif /* CFG_CMD_DATE, CONFIG_TIMESTAMP */ + printf (" Image Type: "); print_type(hdr); printf ("\n"); + printf (" Data Size: %d Bytes = ", ntohl(hdr->ih_size)); + print_size (ntohl(hdr->ih_size), "\n"); + printf (" Load Address: %08x\n", ntohl(hdr->ih_load)); + printf (" Entry Point: %08x\n", ntohl(hdr->ih_ep)); + + if (hdr->ih_type == IH_TYPE_MULTI) { + int i; + ulong len; + ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t)); + + printf (" Contents:\n"); + for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) { + printf (" Image %d: %8ld Bytes = ", i, len); + print_size (len, "\n"); + } + } +} + + +static void +print_type (image_header_t *hdr) +{ + char *os, *arch, *type, *comp; + + switch (hdr->ih_os) { + case IH_OS_INVALID: os = "Invalid OS"; break; + case IH_OS_NETBSD: os = "NetBSD"; break; + case IH_OS_LINUX: os = "Linux"; break; + case IH_OS_VXWORKS: os = "VxWorks"; break; + case IH_OS_QNX: os = "QNX"; break; + case IH_OS_U_BOOT: os = "U-Boot"; break; + default: os = "Unknown OS"; break; + } + + switch (hdr->ih_arch) { + case IH_CPU_INVALID: arch = "Invalid CPU"; break; + case IH_CPU_ALPHA: arch = "Alpha"; break; + case IH_CPU_ARM: arch = "ARM"; break; + case IH_CPU_I386: arch = "Intel x86"; break; + case IH_CPU_IA64: arch = "IA64"; break; + case IH_CPU_MIPS: arch = "MIPS"; break; + case IH_CPU_MIPS64: arch = "MIPS 64 Bit"; break; + case IH_CPU_PPC: arch = "PowerPC"; break; + case IH_CPU_S390: arch = "IBM S390"; break; + case IH_CPU_SH: arch = "SuperH"; break; + case IH_CPU_SPARC: arch = "SPARC"; break; + case IH_CPU_SPARC64: arch = "SPARC 64 Bit"; break; + default: arch = "Unknown Architecture"; break; + } + + switch (hdr->ih_type) { + case IH_TYPE_INVALID: type = "Invalid Image"; break; + case IH_TYPE_STANDALONE:type = "Standalone Program"; break; + case IH_TYPE_KERNEL: type = "Kernel Image"; break; + case IH_TYPE_RAMDISK: type = "RAMDisk Image"; break; + case IH_TYPE_MULTI: type = "Multi-File Image"; break; + case IH_TYPE_FIRMWARE: type = "Firmware"; break; + case IH_TYPE_SCRIPT: type = "Script"; break; + default: type = "Unknown Image"; break; + } + + switch (hdr->ih_comp) { + case IH_COMP_NONE: comp = "uncompressed"; break; + case IH_COMP_GZIP: comp = "gzip compressed"; break; + case IH_COMP_BZIP2: comp = "bzip2 compressed"; break; + default: comp = "unknown compression"; break; + } + + printf ("%s %s %s (%s)", arch, os, type, comp); +} + +#define ZALLOC_ALIGNMENT 16 + +static void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p; + + size *= items; + size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); + + p = malloc (size); + + return (p); +} + +static void zfree(void *x, void *addr, unsigned nb) +{ + free (addr); +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf ("Error: Bad gzipped data\n"); + return (-1); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf ("Error: gunzip out of data in header\n"); + return (-1); + } + + s.zalloc = zalloc; + s.zfree = zfree; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + s.outcb = (cb_func)WATCHDOG_RESET; +#else + s.outcb = Z_NULL; +#endif /* CONFIG_HW_WATCHDOG */ + + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf ("Error: inflateInit2() returned %d\n", r); + return (-1); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf ("Error: inflate() returned %d\n", r); + return (-1); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); + + return (0); +} + +#if (CONFIG_COMMANDS & CFG_CMD_ELF) +static void +do_bootm_vxworks (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + ulong addr, ulong *len_ptr, int verify) +{ + image_header_t *hdr = &header; + char str[80]; + + sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */ + setenv("loadaddr", str); + do_bootvx(cmdtp, 0, 0, NULL); +} + +static void +do_bootm_qnxelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + ulong addr, ulong *len_ptr, int verify) +{ + image_header_t *hdr = &header; + char *local_args[2]; + char str[16]; + + sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */ + local_args[0] = argv[0]; + local_args[1] = str; /* and provide it via the arguments */ + do_bootelf(cmdtp, 0, 2, local_args); +} +#endif /* CFG_CMD_ELF */ |