cmd_bootm.c
来自「U-boot源码 ARM7启动代码」· C语言 代码 · 共 1,650 行 · 第 1/3 页
C
1,650 行
/* * (C) Copyright 2000-2006 * 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 <image.h>#include <malloc.h>#include <zlib.h>#include <bzlib.h>#include <environment.h>#include <asm/byteorder.h>#if defined(CONFIG_OF_LIBFDT)#include <fdt.h>#include <libfdt.h>#include <fdt_support.h>#endif#if defined(CONFIG_OF_FLAT_TREE)#include <ft_build.h>#endifDECLARE_GLOBAL_DATA_PTR;/*cmd_boot.c*/extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE)#include <rtc.h>#endif#ifdef CFG_HUSH_PARSER#include <hush.h>#endif#ifdef CFG_INIT_RAM_LOCK#include <asm/cache.h>#endif#ifdef CONFIG_LOGBUFFER#include <logbuff.h>#endif#ifdef CONFIG_HAS_DATAFLASH#include <dataflash.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)#endifint gunzip (void *, int, unsigned char *, unsigned long *);static void *zalloc(void *, unsigned, unsigned);static void zfree(void *, void *, unsigned);#if defined(CONFIG_CMD_IMI)static int image_info (unsigned long addr);#endif#if defined(CONFIG_CMD_IMLS)#include <flash.h>extern flash_info_t flash_info[]; /* info for FLASH chips */static int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);#endifstatic void print_type (image_header_t *hdr);#ifdef __I386__image_header_t *fake_header(image_header_t *hdr, void *ptr, int size);#endif/* * 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' */#ifdef DEBUGextern int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);#endif#ifdef CONFIG_PPCstatic boot_os_Fcn do_bootm_linux;#elseextern boot_os_Fcn do_bootm_linux;#endif#ifdef CONFIG_SILENT_CONSOLEstatic void fixup_silent_linux (void);#endifstatic boot_os_Fcn do_bootm_netbsd;static boot_os_Fcn do_bootm_rtems;#if defined(CONFIG_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#if defined(CONFIG_ARTOS) && defined(CONFIG_PPC)static boot_os_Fcn do_bootm_artos;#endif#ifdef CONFIG_LYNXKDIstatic boot_os_Fcn do_bootm_lynxkdi;extern void lynxkdi_boot( image_header_t * );#endif#ifndef CFG_BOOTM_LEN#define CFG_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */#endifimage_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; uint unc_len = CFG_BOOTM_LEN; int i, verify; char *name, *s; int (*appl)(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 */#ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash(addr)){ read_dataflash(addr, sizeof(image_header_t), (char *)&header); } else#endif memmove (&header, (char *)addr, sizeof(image_header_t)); if (ntohl(hdr->ih_magic) != IH_MAGIC) {#ifdef __I386__ /* correct image format not implemented yet - fake it */ if (fake_header(hdr, (void*)addr, -1) != NULL) { /* to compensate for the addition below */ addr -= sizeof(image_header_t); /* turnof verify, * fake_header() does not fake the data crc */ verify = 0; } else#endif /* __I386__ */ { puts ("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, (uchar *)data, len) != checksum) { puts ("Bad Header Checksum\n"); show_boot_progress (-2); return 1; } show_boot_progress (3);#ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash(addr)){ len = ntohl(hdr->ih_size) + sizeof(image_header_t); read_dataflash(addr, len, (char *)CFG_LOAD_ADDR); addr = CFG_LOAD_ADDR; }#endif /* 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) { puts (" Verifying Checksum ... "); if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { printf ("Bad Data CRC\n"); show_boot_progress (-3); return 1; } puts ("OK\n"); } show_boot_progress (4); len_ptr = (ulong *)data;#if defined(__ARM__) if (hdr->ih_arch != IH_CPU_ARM)#elif defined(__avr32__) if (hdr->ih_arch != IH_CPU_AVR32)#elif defined(__bfin__) if (hdr->ih_arch != IH_CPU_BLACKFIN)#elif defined(__I386__) if (hdr->ih_arch != IH_CPU_I386)#elif defined(__M68K__) if (hdr->ih_arch != IH_CPU_M68K)#elif defined(__microblaze__) if (hdr->ih_arch != IH_CPU_MICROBLAZE)#elif defined(__mips__) if (hdr->ih_arch != IH_CPU_MIPS)#elif defined(__nios__) if (hdr->ih_arch != IH_CPU_NIOS)#elif defined(__nios2__) if (hdr->ih_arch != IH_CPU_NIOS2)#elif defined(__PPC__) if (hdr->ih_arch != IH_CPU_PPC)#else# error Unknown CPU type#endif { printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch); show_boot_progress (-4); return 1; } show_boot_progress (5); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: name = "Standalone Application"; /* A second argument overwrites the load address */ if (argc > 2) { hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16)); } 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();#ifdef CONFIG_AMIGAONEG3SE /* * We've possible left the caches enabled during * bios emulation, so turn them off again */ icache_disable(); invalidate_l1_instruction_cache(); flush_data_cache(); dcache_disable();#endif switch (hdr->ih_comp) { case IH_COMP_NONE: if(ntohl(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), unc_len, (uchar *)data, &len) != 0) { puts ("GUNZIP ERROR - must RESET board to recover\n"); show_boot_progress (-6); do_reset (cmdtp, flag, argc, argv); } break;#ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: printf (" Uncompressing %s ... ", name); /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load), &unc_len, (char *)data, len, CFG_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i); show_boot_progress (-6); do_reset (cmdtp, flag, argc, argv); } break;#endif /* CONFIG_BZIP2 */ default: if (iflag) enable_interrupts(); printf ("Unimplemented compression type %d\n", hdr->ih_comp); show_boot_progress (-7); return 1; } puts ("OK\n"); show_boot_progress (7); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: if (iflag) enable_interrupts(); /* load (and uncompress), but don't start if "autostart" * is set to "no" */ if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) { char buf[32]; sprintf(buf, "%lX", len); setenv("filesize", buf); return 0; } appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep); (*appl)(argc-1, &argv[1]); return 0; 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:#ifdef CONFIG_SILENT_CONSOLE fixup_silent_linux();#endif 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;#ifdef CONFIG_LYNXKDI case IH_OS_LYNXOS: do_bootm_lynxkdi (cmdtp, flag, argc, argv, addr, len_ptr, verify); break;#endif case IH_OS_RTEMS: do_bootm_rtems (cmdtp, flag, argc, argv, addr, len_ptr, verify); break;#if defined(CONFIG_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#ifdef CONFIG_ARTOS case IH_OS_ARTOS: do_bootm_artos (cmdtp, flag, argc, argv, addr, len_ptr, verify); break;#endif } show_boot_progress (-9);#ifdef DEBUG puts ("\n## Control returned to monitor - resetting...\n"); do_reset (cmdtp, flag, argc, argv);#endif return 1;}U_BOOT_CMD( bootm, CFG_MAXARGS, 1, do_bootm, "bootm - boot application image from memory\n", "[addr [arg ...]]\n - boot application image stored in memory\n" "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" "\t'arg' can be the address of an initrd image\n"#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) "\tWhen booting a Linux kernel which requires a flat device-tree\n" "\ta third argument is required which is the address of the\n" "\tdevice-tree blob. To boot that kernel without an initrd image,\n" "\tuse a '-' for the second argument. If you do not pass a third\n" "\ta bd_info struct will be passed instead\n"#endif);#ifdef CONFIG_SILENT_CONSOLEstatic voidfixup_silent_linux (){ char buf[256], *start, *end; char *cmdline = getenv ("bootargs"); /* Only fix cmdline when requested */ if (!(gd->flags & GD_FLG_SILENT)) return; debug ("before silent fix-up: %s\n", cmdline); if (cmdline) { if ((start = strstr (cmdline, "console=")) != NULL) { end = strchr (start, ' '); strncpy (buf, cmdline, (start - cmdline + 8)); if (end) strcpy (buf + (start - cmdline + 8), end); else buf[start - cmdline + 8] = '\0'; } else { strcpy (buf, cmdline); strcat (buf, " console="); } } else { strcpy (buf, "console="); } setenv ("bootargs", buf); debug ("after silent fix-up: %s\n", buf);}#endif /* CONFIG_SILENT_CONSOLE */#ifdef CONFIG_PPCstatic void __attribute__((noinline))do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], ulong addr, ulong *len_ptr, int verify){ ulong sp; ulong len, checksum; ulong initrd_start, initrd_end; ulong cmd_start, cmd_end; ulong initrd_high; ulong data; int initrd_copy_to_ram = 1; char *cmdline; char *s; bd_t *kbd; void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); image_header_t *hdr = &header;#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT) char *of_flat_tree = NULL; ulong of_data = 0;#endif 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); if (initrd_high == ~0) initrd_copy_to_ram = 0; } else { /* not set, no restrictions to load high */ initrd_high = ~0; }#ifdef CONFIG_LOGBUFFER kbd=gd->bd; /* Prevent initrd from overwriting logbuffer */ if (initrd_high < (kbd->bi_memsize-LOGBUFF_LEN-LOGBUFF_OVERHEAD)) initrd_high = kbd->bi_memsize-LOGBUFF_LEN-LOGBUFF_OVERHEAD; debug ("## Logbuffer at 0x%08lX ", kbd->bi_memsize-LOGBUFF_LEN);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?