| /* |
| * (C) Copyright 2011 |
| * Yuesheng Wang, ZIXC Corporation, WangYueSheng@zte.com.cn. |
| * |
| * 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 |
| */ |
| |
| |
| /* |
| * Multi Image extract |
| */ |
| #include <config.h> |
| #include <common.h> |
| #include <command.h> |
| #include <net.h> |
| #include <linux/mtd/mtd.h> |
| #include <config.h> |
| #include <watchdog.h> |
| #include <environment.h> |
| #include <version.h> |
| #include <search.h> |
| #include <asm/byteorder.h> |
| #include <cmd_downver.h> |
| |
| #define SZ_16M 0x1000000 |
| |
| #include <nand.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| extern enum net_loop_state net_state; |
| extern ulong NetBootFileXferSize; |
| |
| #define CONFIG_SYS_BOOT_LEN 0x40000 //Ô¤Áôboot´óС256K |
| #define CFG_FLASH_SECTOR_SIZE 0x20000 |
| #define CFG_FLASH_BASE 0 |
| |
| /* locals & globals */ |
| search_desc g_search; |
| |
| #define hex2int(c) ((c>='0') && (c<='9') ? (c-'0') : ((c&0xf)+9)) |
| |
| /* Table of CRC32 constants */ |
| static unsigned int crc32_tbl[256]; |
| |
| int do_downver (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
| { |
| int i = 0, region = 1; |
| char arg[256] = {0}; |
| hd_magic_desc *magic = NULL; |
| header_version *header = NULL; |
| |
| if (argc < 2 || argc > CONFIG_SYS_MAXARGS) |
| { |
| printf ("Usage:\n%s\n", cmdtp->usage); |
| return 1; |
| } |
| |
| for (i = 1; i < argc; i++) |
| { |
| /* Download & upgrade intergrated version */ |
| if (! strcmp(argv[i], "allbins")) |
| { |
| //sprintf(arg, "tftp %lx $(bootfile)", (ulong)CONFIG_SYS_LOAD_ADDR); |
| sprintf(arg, "tftp %lx $(bootfile)", (ulong)CONFIG_LOADADDR); |
| if (run_command(arg, flag) >= 0) |
| { |
| /* Return if network loop failed */ |
| if (net_state != NETLOOP_SUCCESS) |
| return 1; |
| |
| /* if (NetBootFileXferSize >= ( nand_info[0].parts->boot_size |
| +nand_info[0].parts->soft0_size)) { |
| printf("Please check file downloaded.\n"); |
| return 1; |
| } |
| |
| magic = (hd_magic_desc *) CONFIG_SYS_LOAD_ADDR; |
| if (magic->ih_magic[0] != CSP_MAGIC0 || |
| magic->ih_magic[1] != CSP_MAGIC1 || |
| magic->ih_magic[2] != CSP_MAGIC2 || |
| magic->ih_magic[3] != CSP_MAGIC3) |
| { |
| printf("Please check file downloaded.\n"); |
| return 1; |
| } |
| |
| header = (header_version *) (CONFIG_SYS_LOAD_ADDR + |
| sizeof(hd_magic_desc) + magic->ih_signatureSize); |
| |
| if (argc >= 3) { |
| region = (int) simple_strtol(argv[2], NULL, 10); |
| if ((region != 1) && (region != 2)) |
| region = 1; |
| } |
| |
| sprintf(arg, "nand erase %lx %lx; nand write %lx %lx %lx;", |
| nand_info[0].parts->soft0_offs, |
| nand_info[0].parts->soft0_size, |
| (ulong)CONFIG_SYS_LOAD_ADDR, |
| nand_info[0].parts->soft0_offs, |
| (ulong)(CSP_HEADER_LEN + header->contend.ih_kern_size)); |
| |
| if (region == 2) { |
| sprintf(arg, "nand erase %lx %lx; nand write %lx %lx %lx;", |
| nand_info[0].parts->soft1_offs, |
| nand_info[0].parts->soft1_size, |
| (ulong)CONFIG_SYS_LOAD_ADDR, |
| nand_info[0].parts->soft1_offs, |
| (ulong)(CSP_HEADER_LEN + header->contend.ih_kern_size)); |
| } |
| |
| #ifndef CFG_HUSH_PARSER |
| if (run_command (arg, flag) == -1) |
| return 1; |
| #else |
| if (parse_string_outer(arg, |
| FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0) |
| return 1; |
| #endif |
| |
| // BootLoader is included in combined software |
| if (header->contend.ih_boot_included) |
| { |
| sprintf(arg, "nand erase %lx %lx; nand write %lx %lx %lx;", |
| nand_info[0].parts->boot_offs, |
| nand_info[0].parts->boot_size, |
| (ulong)(CONFIG_SYS_LOAD_ADDR + header->contend.ih_boot_offset), |
| nand_info[0].parts->boot_offs, |
| (ulong)header->contend.ih_boot_size); |
| |
| #ifndef CFG_HUSH_PARSER |
| if (run_command (arg, flag) == -1) |
| return 1; |
| #else |
| if (parse_string_outer(arg, |
| FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0) |
| return 1; |
| #endif |
| }*/ |
| } |
| else |
| { |
| return -2; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| static unsigned int crc32_reflect (unsigned int ref, char ch) |
| { |
| unsigned int i; |
| unsigned int result=0; |
| |
| /* Swap bit 0 for bit 7, bit 1 for bit 6, etc. */ |
| for (i=1; i<(ch+1); i++) |
| { |
| if (ref & 1) |
| result |= 1 << (ch-i); |
| ref >>= 1; |
| } |
| |
| return (result); |
| } |
| |
| static void crc32_init (void) |
| { |
| /* This is the official polynomial used by CRC32 */ |
| /* in PKZip, WinZip and Ethernet. */ |
| unsigned int i, j; |
| unsigned int ulPolynomial=0x04c11db7; |
| |
| /* 256 values representing ASCII character codes */ |
| for (i=0; i<=0xFF; i++) |
| { |
| crc32_tbl[i] = crc32_reflect(i, 8) << 24; |
| |
| for (j = 0; j < 8; j++) |
| crc32_tbl[i] = (crc32_tbl[i]<<1) ^ (crc32_tbl[i]&(1<<31) ? ulPolynomial:0); |
| |
| crc32_tbl[i] = crc32_reflect(crc32_tbl[i], 32); |
| } |
| } |
| |
| #if 0 |
| static unsigned int crc32_accumulate (char *s, unsigned int len) |
| { |
| /* |
| * Be sure to use unsigned variables, because negative |
| * values introduce high bits where zero bits are required |
| */ |
| unsigned int total; |
| unsigned char *data; |
| unsigned int crc=0xffffffff; |
| |
| total = len; |
| data = (unsigned char*)s; |
| |
| /* |
| * Perform the algorithm on each character in the string, |
| * using the lookup table values |
| */ |
| while (total--) |
| { |
| crc = (crc>>8) ^ crc32_tbl[(crc&0xff) ^ *data++]; |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| if(total%0x80000 == 0) |
| { |
| WATCHDOG_RESET(); |
| } |
| #endif |
| } |
| |
| /* Exclusive OR the result with the beginning value */ |
| return (crc^0xffffffff); |
| } |
| |
| #ifdef CONFIG_ZTE_NAND_SKIP_BAD_IN_MTD |
| /****************************************************************** |
| * º¯ÊýÃû³Æ£º do_search |
| * ¹¦ÄÜÃèÊö£º ËÑË÷FlashÉϵÄÍêÕûµÄ°æ±¾ |
| * ÊäÈë²ÎÊý£º long start : ËÑË÷ÆðʼµØÖ· |
| * long end : ËÑË÷½áÊøµØÖ· |
| * long step : ËÑË÷²½½ø³¤¶È |
| * search_desc *search : ËÑË÷½á¹û |
| * Êä³ö²ÎÊý£º ÎÞ |
| * ·µ »Ø Öµ£º ³É¹¦·µ»Ø0 |
| * ÆäËü˵Ã÷£º ÎÞ |
| * ÐÞ¸ÄÈÕÆÚ °æ±¾ºÅ ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ |
| * ---------------------------------------------------------------- |
| * 2009/11/30 V1.0 ÍõÔÂÉú ´´½¨ |
| ******************************************************************/ |
| int do_search (unsigned int start, unsigned int end, unsigned int step, |
| search_desc *search) |
| { |
| long rate=0, index=-1; |
| loff_t addr = 0, addrEnd = 0; |
| unsigned int lseek=0; |
| hd_magic_desc *magic=NULL; |
| header_version *header=NULL; |
| unsigned int crcret=0, crclen=0; |
| unsigned char flags=0; |
| #if defined(CONFIG_CMD_NAND) |
| nand_info_t *nand=&nand_info[nand_curr_device]; |
| size_t readlen = CSP_HEADER_LEN; |
| unsigned char *pbuff = (unsigned char *) CONFIG_SYS_LOAD_ADDR; |
| #endif |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET (); |
| #endif |
| |
| memset ((char *)search, 0, sizeof(search_desc)); |
| |
| if (step != 0) /* ËÑË÷²½½ø³¤¶È */ |
| rate = step; |
| else |
| rate = CFG_FLASH_SECTOR_SIZE; |
| |
| crc32_init (); |
| |
| addr = CFG_FLASH_BASE + start; /* ËÑË÷ÆðʼµØÖ· */ |
| addrEnd = CFG_FLASH_BASE + end; /* ËÑË÷½áÊøµØÖ· */ |
| |
| while (addr < addrEnd) /* ´ÓµÍµØÖ·¿Õ¼äÏò¸ßµØÖ·¿Õ¼äËÑË÷ */ |
| { |
| #if defined(CONFIG_CMD_NAND) |
| if (nand_block_isbad (nand, addr & ~(nand->erasesize - 1))) { |
| printf("skip bad block...addr=0x%llx\n", addr); |
| addr += rate; |
| continue; |
| } |
| |
| /* nand read 256 bytes */ |
| nand_read(nand, addr, &readlen, pbuff); |
| magic = (hd_magic_desc *) pbuff; |
| #else |
| magic = (hd_magic_desc *)addr; |
| #endif |
| |
| /* ¼ì²é°æ±¾Í·µÄ»ÃÊýÊÇ·ñ´æÔÚ */ |
| if ((magic->ih_magic[0] == CSP_MAGIC0) && |
| (magic->ih_magic[1] == CSP_MAGIC1) && |
| (magic->ih_magic[2] == CSP_MAGIC2) && |
| (magic->ih_magic[3] == CSP_MAGIC3)) |
| { |
| flags = 0x00; index++; |
| printf("addr=%x\n", (int)addr); |
| |
| /* ¼ì²é°æ±¾Í·µÄºÍУÑé */ |
| lseek = (unsigned int)(pbuff + sizeof(hd_magic_desc) + magic->ih_signatureSize); |
| header = (header_version *)(lseek); |
| crclen = sizeof(hd_general_desc) + IH_HCRC_OFFSET; |
| crcret = crc32_accumulate ((char *)lseek, crclen); |
| |
| if (crcret == header->contend.ih_hcrc) |
| { |
| flags |= CFG_TB_HEADER; |
| search->result[index].flags = flags; |
| /* ÄÚºËÈë¿ÚµØÖ· = °æ±¾Í·Æ«ÒÆ + °æ±¾Í·³¤¶È */ |
| search->result[index].entry = addr + CSP_HEADER_LEN; |
| } |
| else |
| { |
| printf("header crc error 0x%08x,add=0x%08x\n,binheadercrc=0x%08x\n", |
| crcret,(int)addr,header->contend.ih_hcrc); |
| addr += rate; /* ÏÂÒ»¸öËÑË÷µØÖ· */ |
| continue; |
| } |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET(); |
| #endif |
| |
| if (header->contend.ih_isnewly==IMAGE_NEW) |
| flags |= CFG_TB_LATELY; |
| if (header->contend.ih_fromsync!=IMAGE_UPGRADE) |
| flags |= CFG_TB_SYNCED; |
| |
| #if defined(CONFIG_CMD_NAND) |
| if (header->contend.ih_isfull == CFG_IMAGE_OKAY) |
| #else |
| if ((flags & CFG_TB_KERNEL) && (flags & CFG_TB_ROOTFS)) |
| #endif |
| { |
| flags |= CFG_TB_INTACT; |
| |
| search->result[index].flags = flags; |
| /* ÄÚºËÈë¿ÚµØÖ· = °æ±¾Í·Æ«ÒÆ + °æ±¾Í·³¤¶È */ |
| search->result[index].entry = addr + CSP_HEADER_LEN; |
| search->result[index].ih_size = ALIGN_SIZE16(CSP_HEADER_LEN + |
| header->contend.ih_kern_size); |
| search->total = index + 1; /* ÓÐЧ°æ±¾¸öÊý */ |
| } |
| } |
| |
| if (search->total >= 2) |
| break; |
| addr += rate; /* ÏÂÒ»¸öËÑË÷µØÖ· */ |
| } |
| |
| if (search->total <= 0) { |
| printf("none fully-formed version\n"); |
| } |
| |
| return (0); |
| } |
| |
| /******************************************************************************* |
| * |
| * do_startup - select a valid runnable version and startup it |
| * |
| * This function select a valid runnable version and startup it. If there are |
| * more runnable versions than one, this function can judge which version is |
| * usable according to its integrality, where form upgrading or synchronization |
| * and whether it is a new version. |
| * |
| * RETURNS: OK. |
| */ |
| |
| int do_startup (search_desc *search) |
| { |
| int select=-1, retry_cnt = -1; |
| unsigned char buffer[4096] = {0}; |
| int iret = -1, i = 0; |
| char tmp[20] = {0}; |
| unsigned int crcret=0, crclen=0, lseek=0; |
| hd_magic_desc *magic=NULL; |
| header_version *header=NULL; |
| loff_t mtd_offset = 0; |
| uint32_t mtd_length = 0; |
| int mtdpart = 0; |
| |
| if (search->total == 1) |
| { |
| if ((search->result[0].flags & CFG_TB_HEADER) && |
| (search->result[0].flags & CFG_TB_INTACT)) |
| { |
| select = 0; |
| } |
| else if ((search->result[1].flags & CFG_TB_HEADER) && |
| (search->result[1].flags & CFG_TB_INTACT)) |
| { |
| select = 1; |
| } |
| } |
| else if (search->total == 2) |
| { |
| retry_cnt = 1; |
| /* °æ±¾0ÍêÕûÇÒΪа汾 */ |
| if ((search->result[0].flags & CFG_TB_HEADER) && |
| (search->result[0].flags & CFG_TB_INTACT) && |
| (search->result[0].flags & CFG_TB_LATELY)) |
| { |
| select = 0; |
| } |
| /* °æ±¾1ÍêÕûÇÒΪа汾 */ |
| else if ((search->result[1].flags & CFG_TB_HEADER) && |
| (search->result[1].flags & CFG_TB_INTACT) && |
| (search->result[1].flags & CFG_TB_LATELY)) |
| { |
| select = 1; |
| } |
| else |
| { |
| select = 0; |
| } |
| } |
| |
| printf("select=0x%x\n",select); |
| |
| /* ËÑË÷OMCIÆô¶¯Ñ¡Ïî²ÎÊýÇø£¬Æô¶¯OMCIÖ¸¶¨µÄ»î¶¯°æ±¾ */ |
| #undef CFG_OMCI_OFFSET |
| #define CFG_OMCI_OFFSET 0x02a00000 |
| mtd_offset = 0; |
| mtd_length = 4096; |
| mtdpart = MTD_OTHER; |
| |
| iret = nand_read_skip_bad_(mtdpart, mtd_offset, mtd_length, &buffer[0]); |
| if (iret < 0) |
| { |
| printf("read other failed!\n"); |
| } |
| |
| if (buffer[0]!=0xff || buffer[1]!=0xff || |
| buffer[2]!=0xff || buffer[3]!=0xff) |
| { |
| for (i=0; i<sizeof(buffer)-strlen("BootImageNum"); ) |
| { |
| iret = memcmp(&buffer[i], "BootImageNum", strlen("BootImageNum")); |
| if (iret==0) |
| { |
| if (i==0) break; |
| |
| if ((i>0) && (buffer[i-1]==',') && |
| (buffer[i+strlen("BootImageNum")]=='=')) |
| { |
| break; |
| } |
| else |
| { |
| i++; |
| continue; |
| } |
| } |
| else |
| { |
| i++; |
| } |
| } |
| |
| if (iret==0) /* Æ¥Åäµ½ "BootImageNum" ¹Ø¼ü×Ö */ |
| { |
| if (i >= 4096 - strlen("BootImageNum=0x00000001")) |
| { |
| printf("buffer overflow!!!\n"); |
| return -1; |
| } |
| |
| strncpy(tmp, (char *)&buffer[i + strlen("BootImageNum") + 1], 10); |
| printf("BootImageNum=%s,%ld\n", tmp, simple_strtol(tmp, NULL, 16)); |
| if (simple_strtol(tmp, NULL, 16)==0 || |
| simple_strtol(tmp, NULL, 16)==1) |
| { |
| if (search->total >= 2) |
| { |
| select = simple_strtol(tmp, NULL, 16); |
| if (!(search->result[select].flags & CFG_TB_INTACT) && |
| (search->result[select?0:1].flags & CFG_TB_INTACT)) |
| { |
| select = select ? 0 : 1; |
| } |
| } |
| } |
| } |
| } |
| |
| printf("select=0x%x\n",select); |
| printf("search=0x%x\n",search->total); |
| |
| if ( select < 0 ) /* ûÓпÉÔËÐеÄÍêÕû°æ±¾ */ |
| { |
| return (-1); |
| } |
| |
| #if defined(CONFIG_CMD_NAND) |
| retry_find: |
| mtd_offset = 0; |
| mtd_length = search->result[select].ih_size; |
| printf("search->result[select].entry=%lx\n", search->result[select].entry); |
| if (((search->result[select].entry - CSP_HEADER_LEN) >= nand_info[0].parts->soft1_offs) |
| &&((search->result[select].entry - CSP_HEADER_LEN) < nand_info[0].parts->soft1_offs +nand_info[0].parts->soft1_size)) |
| { |
| mtdpart = MTD_KERNEL1; |
| } |
| else |
| { |
| mtdpart = MTD_KERNEL; |
| } |
| |
| iret = nand_read_skip_bad_(mtdpart, mtd_offset, mtd_length, (u_char *)CONFIG_SYS_LOAD_ADDR); |
| |
| if (iret == 0) { |
| magic = (hd_magic_desc *) CONFIG_SYS_LOAD_ADDR; |
| if (magic->ih_magic[0] == CSP_MAGIC0 && |
| magic->ih_magic[1] == CSP_MAGIC1 && |
| magic->ih_magic[2] == CSP_MAGIC2 && |
| magic->ih_magic[3] == CSP_MAGIC3) |
| { |
| header = (header_version *)(CONFIG_SYS_LOAD_ADDR + |
| sizeof(hd_magic_desc) + magic->ih_signatureSize); |
| lseek = CONFIG_SYS_LOAD_ADDR + CSP_HEADER_LEN; |
| crclen = header->contend.ih_kern_size; |
| crcret = crc32_accumulate ((char *)lseek, crclen); |
| |
| if (crcret == header->contend.ih_kern_dcrc) |
| { |
| /* Has independent root filesystem */ |
| if (header->contend.ih_fs_size > 0) |
| { |
| printf("invalid fs type, %s, %d!\n", __FUNCTION__, __LINE__); |
| return -1; |
| } |
| else { |
| search->result[select].fstype = CFG_FS_INITRAM; |
| } |
| } |
| else { |
| printf("vmlinuz crc error 0x%08x\n", crcret); |
| goto fail_out; |
| } |
| } |
| else { |
| printf("magic not found\n"); |
| goto fail_out; |
| } |
| } |
| |
| return (select); |
| |
| fail_out: |
| if ((search->total >= 2) && (--retry_cnt >= 0)) { |
| select = (select > 0) ? 0 : 1; |
| goto retry_find; |
| } |
| else { |
| return (-1); |
| } |
| #endif |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * do_settings - configure necessary envirnment variables and save them in flash |
| * |
| * This function configure necessary envirnment variables, such as bootversion, |
| * baseaddress, bootcmd, memsize and etc., and save them in flash. |
| * |
| * RETURNS: OK. |
| */ |
| |
| int do_settings (int num, const search_desc *search) |
| { |
| long bSaved=0, lseek=0; |
| char *s = NULL; |
| char arg[64] = {0}, cmdline[256] = {0}; |
| int select=num; |
| |
| loff_t mtd_offset = 0; |
| uint32_t mtd_length = 0; |
| int mtdpart = MTD_BOOT; |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET(); |
| #endif |
| |
| setenv("ipaddr", "192.168.1.1"); |
| setenv("serverip", "192.168.1.100"); |
| |
| sprintf (arg, "%dM", CONFIG_SYS_SDRAM_SIZE>>20); |
| s = getenv ("memsize"); |
| if (((s!=NULL) && (strncmp(s, arg, 3)!=0)) || |
| (s==NULL)) { |
| setenv ("memsize", arg); |
| bSaved = 1; |
| } |
| |
| /* ÉèÖû·¾³±äÁ¿£bootcmd */ |
| if (select >= 0) |
| { |
| if (search->result[select].fstype == CFG_FS_SQUASH) |
| { |
| sprintf (cmdline, "%s %s", |
| "setenv bootargs root=/dev/mtdblock4 rootfstype=squashfs", |
| "console=$(consoledev),$(baudrate);"); |
| } |
| |
| switch (search->result[select].fstype) |
| { |
| case CFG_FS_JFFS2: |
| case CFG_FS_SQUASH: |
| if (search->result[select].entry >= |
| (nand_info[0].parts->soft0_offs + |
| nand_info[0].parts->soft0_size)) |
| { |
| sprintf (cmdline, "%s %s %s", |
| (search->result[select].fstype==CFG_FS_JFFS2) ? |
| "setenv bootargs root=/dev/mtdblock7 rw rootfstype=jffs2" : |
| "setenv bootargs root=/dev/mtdblock7 rootfstype=squashfs", |
| "console=$(consoledev),$(baudrate)", |
| "flashsize=$(flashsize) mem=$(memsize);"); |
| } |
| break; |
| |
| case CFG_FS_INITRAM: |
| sprintf (cmdline, "%s", |
| "setenv bootargs console=$(console) root=/dev/ram0 rw rdinit=/sbin/init mem=$(memsize);"); |
| break; |
| case CFG_FS_NONE: |
| default: |
| printf("invalid fstype...!\n"); |
| break; |
| } |
| } |
| |
| sprintf (arg, "bootm 0x%x;", CONFIG_SYS_LOAD_ADDR + CSP_HEADER_LEN); |
| strcat (cmdline, arg); |
| s = getenv ("bootcmd"); |
| if (((s!=NULL) && (strncmp(s, cmdline, strlen(cmdline))!=0)) || |
| (s==NULL)) { |
| setenv ("bootcmd", cmdline); |
| bSaved = 1; |
| } |
| |
| if (select < 0) { /* ûÓпÉÔËÐеÄÍêÕû°æ±¾ */ |
| run_command ("setenv bootcmd", 0); |
| return -1; |
| } |
| |
| if (bSaved) { /* ±£´æ»·¾³±äÁ¿ */ |
| run_command ("saveenv", 0); |
| } |
| |
| mtd_offset = 0; |
| |
| mtd_length = CONFIG_SYS_BOOT_LEN; |
| |
| nand_read_skip_bad_(mtdpart, mtd_offset, mtd_length, (u_char *)(CONFIG_SYS_LOAD_ADDR + SZ_16M)); |
| |
| for (lseek = (CONFIG_SYS_LOAD_ADDR + SZ_16M + CONFIG_SYS_BOOT_LEN); |
| lseek > CONFIG_SYS_LOAD_ADDR + SZ_16M; |
| lseek -= CFG_ALLIGN_SIZE) |
| { |
| if ((((hd_boot_file *)lseek)->btMagic[0]==CSP_MAGIC3) && |
| (((hd_boot_file *)lseek)->btMagic[1]==CSP_MAGIC2) && |
| (((hd_boot_file *)lseek)->btMagic[2]==CSP_MAGIC1) && |
| (((hd_boot_file *)lseek)->btMagic[3]==CSP_MAGIC0)) |
| { |
| printf("lseek=0x%lx\n", lseek); |
| memset(cmdline, 0, sizeof(cmdline)); |
| sprintf(cmdline, "U-Boot %s %c%c%c%c%c%c%c%c%c%c%c%c%c%c ", ((hd_boot_file *)lseek)->btNumbers, |
| ((hd_boot_file *)lseek)->btCtime[0], |
| ((hd_boot_file *)lseek)->btCtime[1], |
| ((hd_boot_file *)lseek)->btCtime[2], |
| ((hd_boot_file *)lseek)->btCtime[3], |
| ((hd_boot_file *)lseek)->btCtime[5], |
| ((hd_boot_file *)lseek)->btCtime[6], |
| ((hd_boot_file *)lseek)->btCtime[8], |
| ((hd_boot_file *)lseek)->btCtime[9], |
| ((hd_boot_file *)lseek)->btCtime[11], |
| ((hd_boot_file *)lseek)->btCtime[12], |
| ((hd_boot_file *)lseek)->btCtime[14], |
| ((hd_boot_file *)lseek)->btCtime[15], |
| ((hd_boot_file *)lseek)->btCtime[17], |
| ((hd_boot_file *)lseek)->btCtime[18]); |
| |
| printf("cmdline=%s\n", cmdline); |
| break; |
| } |
| } |
| if(lseek>=(CONFIG_SYS_LOAD_ADDR + SZ_16M + CONFIG_SYS_BOOT_LEN)) |
| { |
| printf("error in do_settings!\n"); |
| return -1; |
| } |
| |
| sprintf (arg, "0x%lx ", search->result[select].entry-CSP_HEADER_LEN); |
| strcat (cmdline, arg); |
| if(search->total==1) |
| {/*Ë«°æ±¾µÄÒì³£Çé¿ö:Ö»Óа汾2*/ |
| if(search->result[select].entry <(nand_info[0].parts->soft0_offs + nand_info[0].parts->soft0_size)) |
| { |
| sprintf (arg, "0x%1x 0x%02x 0x%02x", 0, search->result[0].flags, search->result[1].flags); |
| } |
| else |
| { |
| sprintf (arg, "0x%1x 0x%02x 0x%02x", 1, search->result[1].flags, search->result[0].flags); |
| } |
| } |
| else |
| { |
| sprintf (arg, "0x%1x 0x%02x 0x%02x", select, search->result[0].flags, search->result[1].flags); |
| } |
| |
| strcat (cmdline, arg); |
| s = getenv ("versioninfo"); |
| if (((s!=NULL) && (strncmp(s, cmdline, strlen(cmdline))!=0)) || |
| (s==NULL)) |
| { |
| setenv ("versioninfo", cmdline); |
| bSaved = 1; |
| } |
| |
| |
| if (bSaved) /* ±£´æ»·¾³±äÁ¿ */ |
| { |
| run_command ("saveenv", 0); |
| } |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET(); |
| #endif |
| |
| return (0); |
| } |
| #else |
| |
| /****************************************************************** |
| * º¯ÊýÃû³Æ£º do_search |
| * ¹¦ÄÜÃèÊö£º ËÑË÷FlashÉϵÄÍêÕûµÄ°æ±¾ |
| * ÊäÈë²ÎÊý£º long start : ËÑË÷ÆðʼµØÖ· |
| * long end : ËÑË÷½áÊøµØÖ· |
| * long step : ËÑË÷²½½ø³¤¶È |
| * search_desc *search : ËÑË÷½á¹û |
| * Êä³ö²ÎÊý£º ÎÞ |
| * ·µ »Ø Öµ£º ³É¹¦·µ»Ø0 |
| * ÆäËü˵Ã÷£º ÎÞ |
| * ÐÞ¸ÄÈÕÆÚ °æ±¾ºÅ ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ |
| * ---------------------------------------------------------------- |
| * 2009/11/30 V1.0 ÍõÔÂÉú ´´½¨ |
| ******************************************************************/ |
| int do_search (unsigned int start, unsigned int end, unsigned int step, |
| search_desc *search) |
| { |
| long rate=0, index=-1; |
| unsigned int addr = 0, addrEnd = 0; |
| unsigned int lseek=0; |
| hd_magic_desc *magic=NULL; |
| header_version *header=NULL; |
| unsigned int crcret=0, crclen=0; |
| unsigned char flags=0; |
| #if defined(CONFIG_CMD_NAND) |
| nand_info_t *nand=&nand_info[nand_curr_device]; |
| unsigned int readlen = CSP_HEADER_LEN; |
| unsigned int pbuff = CONFIG_SYS_LOAD_ADDR; |
| unsigned int len_inc_bad = 0; |
| #endif |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET (); |
| #endif |
| |
| memset ((char *)search, 0, sizeof(search_desc)); |
| |
| if (step != 0) /* ËÑË÷²½½ø³¤¶È */ |
| rate = step; |
| else |
| rate = CFG_FLASH_SECTOR_SIZE; |
| |
| crc32_init (); |
| |
| addr = CFG_FLASH_BASE + start; /* ËÑË÷ÆðʼµØÖ· */ |
| addrEnd = CFG_FLASH_BASE + end; /* ËÑË÷½áÊøµØÖ· */ |
| |
| while (addr < addrEnd) /* ´ÓµÍµØÖ·¿Õ¼äÏò¸ßµØÖ·¿Õ¼äËÑË÷ */ |
| { |
| #if defined(CONFIG_CMD_NAND) |
| if (nand_block_isbad (nand, addr & ~(nand->erasesize - 1))) { |
| printf("skip bad block...addr=0x%8x\n", addr); |
| addr += rate; |
| len_inc_bad += rate; |
| continue; |
| } |
| |
| /* nand read 256 bytes */ |
| nand_read(nand, addr, &readlen, (unsigned char *)pbuff); |
| magic = (hd_magic_desc *) pbuff; |
| #else |
| magic = (hd_magic_desc *)addr; |
| #endif |
| |
| /* ¼ì²é°æ±¾Í·µÄ»ÃÊýÊÇ·ñ´æÔÚ */ |
| if ((magic->ih_magic[0] == CSP_MAGIC0) && |
| (magic->ih_magic[1] == CSP_MAGIC1) && |
| (magic->ih_magic[2] == CSP_MAGIC2) && |
| (magic->ih_magic[3] == CSP_MAGIC3)) |
| { |
| flags = 0x00; index++; |
| printf("addr=%x\n", (int)addr); |
| |
| /* ¼ì²é°æ±¾Í·µÄºÍУÑé */ |
| lseek = pbuff + sizeof(hd_magic_desc) + magic->ih_signatureSize; |
| header = (header_version *)(lseek); |
| crclen = sizeof(hd_general_desc) + IH_HCRC_OFFSET; |
| crcret = crc32_accumulate ((char *)lseek, crclen); |
| |
| if (crcret == header->contend.ih_hcrc) |
| { |
| flags |= CFG_TB_HEADER; |
| search->result[index].flags = flags; |
| /* ÄÚºËÈë¿ÚµØÖ· = °æ±¾Í·Æ«ÒÆ + °æ±¾Í·³¤¶È */ |
| search->result[index].entry = addr + CSP_HEADER_LEN; |
| } |
| else |
| { |
| printf("header crc error 0x%08x,add=0x%08x\n,binheadercrc=0x%08x\n", |
| crcret,addr,header->contend.ih_hcrc); |
| addr += rate; /* ÏÂÒ»¸öËÑË÷µØÖ· */ |
| continue; |
| } |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET(); |
| #endif |
| |
| if (header->contend.ih_isnewly==IMAGE_NEW) |
| flags |= CFG_TB_LATELY; |
| if (header->contend.ih_fromsync!=IMAGE_UPGRADE) |
| flags |= CFG_TB_SYNCED; |
| |
| #if defined(CONFIG_CMD_NAND) |
| if (header->contend.ih_isfull == CFG_IMAGE_OKAY) |
| #else |
| if ((flags & CFG_TB_KERNEL) && (flags & CFG_TB_ROOTFS)) |
| #endif |
| { |
| flags |= CFG_TB_INTACT; |
| |
| search->result[index].flags = flags; |
| /* ÄÚºËÈë¿ÚµØÖ· = °æ±¾Í·Æ«ÒÆ + °æ±¾Í·³¤¶È */ |
| search->result[index].entry = addr + CSP_HEADER_LEN-len_inc_bad; |
| search->result[index].ih_size = ALIGN_SIZE16(CSP_HEADER_LEN + |
| header->contend.ih_kern_size); |
| search->total = index + 1; /* ÓÐЧ°æ±¾¸öÊý */ |
| } |
| } |
| |
| if (search->total >= 2) |
| break; |
| addr += rate; /* ÏÂÒ»¸öËÑË÷µØÖ· */ |
| } |
| |
| if (search->total <= 0) { |
| printf("none fully-formed version\n"); |
| } |
| |
| return (0); |
| } |
| |
| /******************************************************************************* |
| * |
| * do_startup - select a valid runnable version and startup it |
| * |
| * This function select a valid runnable version and startup it. If there are |
| * more runnable versions than one, this function can judge which version is |
| * usable according to its integrality, where form upgrading or synchronization |
| * and whether it is a new version. |
| * |
| * RETURNS: OK. |
| */ |
| |
| int do_startup (search_desc *search) |
| { |
| int select=-1, retry_cnt = -1; |
| unsigned char buffer[256] = {0}; |
| char cmd[64] = {0}; |
| int iret = -1, i = 0; |
| char tmp[20] = {0}; |
| unsigned int badlen=0, versize=0, readlen=4, node = 0; |
| unsigned int crcret=0, crclen=0, lseek=0; |
| hd_magic_desc *magic=NULL; |
| header_version *header=NULL; |
| #if defined(CONFIG_CMD_NAND) |
| nand_info_t *nand=&nand_info[nand_curr_device]; |
| #endif |
| |
| if (search->total == 1) |
| { |
| if ((search->result[0].flags & CFG_TB_HEADER) && |
| (search->result[0].flags & CFG_TB_INTACT)) |
| { |
| select = 0; |
| } |
| else if ((search->result[1].flags & CFG_TB_HEADER) && |
| (search->result[1].flags & CFG_TB_INTACT)) |
| { |
| select = 1; |
| } |
| } |
| else if (search->total == 2) |
| { |
| retry_cnt = 1; |
| /* °æ±¾0ÍêÕûÇÒΪа汾 */ |
| if ((search->result[0].flags & CFG_TB_HEADER) && |
| (search->result[0].flags & CFG_TB_INTACT) && |
| (search->result[0].flags & CFG_TB_LATELY)) |
| { |
| select = 0; |
| } |
| /* °æ±¾1ÍêÕûÇÒΪа汾 */ |
| else if ((search->result[1].flags & CFG_TB_HEADER) && |
| (search->result[1].flags & CFG_TB_INTACT) && |
| (search->result[1].flags & CFG_TB_LATELY)) |
| { |
| select = 1; |
| } |
| else |
| { |
| select = 0; |
| } |
| } |
| |
| printf("select=0x%x\n",select); |
| |
| /* ËÑË÷OMCIÆô¶¯Ñ¡Ïî²ÎÊýÇø£¬Æô¶¯OMCIÖ¸¶¨µÄ»î¶¯°æ±¾ */ |
| #undef CFG_OMCI_OFFSET |
| #define CFG_OMCI_OFFSET 0x02a00000 |
| sprintf(cmd, "nand read %lx %8x %x", (ulong)buffer, CFG_OMCI_OFFSET, 256); |
| iret = run_command(cmd, 0); |
| |
| if (buffer[0]!=0xff || buffer[1]!=0xff || |
| buffer[2]!=0xff || buffer[3]!=0xff) |
| { |
| for (i=0; i<sizeof(buffer)-strlen("BootImageNum"); ) |
| { |
| iret = memcmp(&buffer[i], "BootImageNum", strlen("BootImageNum")); |
| if (iret==0) |
| { |
| if (i==0) break; |
| |
| if ((i>0) && (buffer[i-1]==',') && |
| (buffer[i+strlen("BootImageNum")]=='=')) |
| { |
| break; |
| } |
| else |
| { |
| i++; |
| continue; |
| } |
| } |
| else |
| { |
| i++; |
| } |
| } |
| |
| if (iret==0) /* Æ¥Åäµ½ "BootImageNum" ¹Ø¼ü×Ö */ |
| { |
| if (i >= 256 - strlen("BootImageNum=0x00000001")) |
| { |
| printf("buffer overflow!!!\n"); |
| return -1; |
| } |
| |
| strncpy(tmp, (char *)&buffer[i + strlen("BootImageNum") + 1], 10); |
| printf("BootImageNum=%s,%ld\n", tmp, simple_strtol(tmp, NULL, 16)); |
| if (simple_strtol(tmp, NULL, 16)==0 || |
| simple_strtol(tmp, NULL, 16)==1) |
| { |
| if (search->total >= 2) |
| { |
| select = simple_strtol(tmp, NULL, 16); |
| if (!(search->result[select].flags & CFG_TB_INTACT) && |
| (search->result[select?0:1].flags & CFG_TB_INTACT)) |
| { |
| select = select ? 0 : 1; |
| } |
| } |
| } |
| } |
| } |
| |
| printf("select=0x%x\n",select); |
| printf("search=0x%x\n",search->total); |
| |
| if ( select < 0 ) /* ûÓпÉÔËÐеÄÍêÕû°æ±¾ */ |
| { |
| return (-1); |
| } |
| |
| #if defined(CONFIG_CMD_NAND) |
| retry_find: |
| sprintf(cmd, "nand read %lx %lx %8x;", (ulong)CONFIG_SYS_LOAD_ADDR, |
| search->result[select].entry - CSP_HEADER_LEN, |
| search->result[select].ih_size); |
| |
| if (run_command(cmd, 0) >= 0) { |
| magic = (hd_magic_desc *) CONFIG_SYS_LOAD_ADDR; |
| if (magic->ih_magic[0] == CSP_MAGIC0 && |
| magic->ih_magic[1] == CSP_MAGIC1 && |
| magic->ih_magic[2] == CSP_MAGIC2 && |
| magic->ih_magic[3] == CSP_MAGIC3) |
| { |
| header = (header_version *)(CONFIG_SYS_LOAD_ADDR + |
| sizeof(hd_magic_desc) + magic->ih_signatureSize); |
| lseek = CONFIG_SYS_LOAD_ADDR + CSP_HEADER_LEN; |
| crclen = header->contend.ih_kern_size; |
| crcret = crc32_accumulate ((char *)lseek, crclen); |
| |
| if (crcret == header->contend.ih_kern_dcrc) |
| { |
| /* Has independent root filesystem */ |
| if (header->contend.ih_fs_size > 0) |
| { |
| printf("invalid fs type, %s, %d!\n", __FUNCTION__, __LINE__); |
| return -1; |
| } |
| else |
| { |
| search->result[select].fstype = CFG_FS_INITRAM; |
| } |
| } |
| else { |
| printf("vmlinuz crc error 0x%08x\n", crcret); |
| goto fail_out; |
| } |
| } |
| else { |
| printf("magic not found\n"); |
| goto fail_out; |
| } |
| } |
| |
| return (select); |
| |
| fail_out: |
| if ((search->total >= 2) && (--retry_cnt >= 0)) { |
| select = (select > 0) ? 0 : 1; |
| goto retry_find; |
| } |
| else { |
| return (-1); |
| } |
| #endif |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * do_settings - configure necessary envirnment variables and save them in flash |
| * |
| * This function configure necessary envirnment variables, such as bootversion, |
| * baseaddress, bootcmd, memsize and etc., and save them in flash. |
| * |
| * RETURNS: OK. |
| */ |
| |
| int do_settings (int num, const search_desc *search) |
| { |
| long bSaved=0, lseek=0; |
| char *s = NULL; |
| char arg[64] = {0}, cmdline[256] = {0}; |
| int select=num; |
| char parm[64] = {0}; |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET(); |
| #endif |
| |
| setenv("ipaddr", "192.168.1.1"); |
| setenv("serverip", "192.168.1.100"); |
| |
| sprintf (arg, "%dM", CONFIG_SYS_SDRAM_SIZE>>20); |
| s = getenv ("memsize"); |
| if (((s!=NULL) && (strncmp(s, arg, 3)!=0)) || |
| (s==NULL)) { |
| setenv ("memsize", arg); |
| bSaved = 1; |
| } |
| |
| /* ÉèÖû·¾³±äÁ¿£bootcmd */ |
| if (select >= 0) |
| { |
| if (search->result[select].fstype == CFG_FS_SQUASH) |
| { |
| sprintf (cmdline, "%s %s", |
| "setenv bootargs root=/dev/mtdblock4 rootfstype=squashfs", |
| "console=$(consoledev),$(baudrate);"); |
| } |
| |
| switch (search->result[select].fstype) |
| { |
| case CFG_FS_JFFS2: |
| case CFG_FS_SQUASH: |
| if (search->result[select].entry >= |
| (nand_info[0].parts->soft0_offs + |
| nand_info[0].parts->soft0_size)) |
| { |
| sprintf (cmdline, "%s %s %s", |
| (search->result[select].fstype==CFG_FS_JFFS2) ? |
| "setenv bootargs root=/dev/mtdblock7 rw rootfstype=jffs2" : |
| "setenv bootargs root=/dev/mtdblock7 rootfstype=squashfs", |
| "console=$(consoledev),$(baudrate)", |
| "flashsize=$(flashsize) mem=$(memsize);"); |
| } |
| break; |
| |
| case CFG_FS_INITRAM: |
| sprintf (cmdline, "%s", |
| "setenv bootargs console=$(console) root=/dev/ram0 rw rdinit=/sbin/init mem=$(memsize);"); |
| break; |
| case CFG_FS_NONE: |
| default: |
| printf("invalid fstype...!\n"); |
| break; |
| } |
| } |
| |
| sprintf (arg, "bootm 0x%8x;", CONFIG_SYS_LOAD_ADDR + CSP_HEADER_LEN); |
| strcat (cmdline, arg); |
| s = getenv ("bootcmd"); |
| if (((s!=NULL) && (strncmp(s, cmdline, strlen(cmdline))!=0)) || |
| (s==NULL)) { |
| setenv ("bootcmd", cmdline); |
| bSaved = 1; |
| } |
| |
| if (select < 0) { /* ûÓпÉÔËÐеÄÍêÕû°æ±¾ */ |
| run_command ("setenv bootcmd", 0); |
| return -1; |
| } |
| |
| if (bSaved) { /* ±£´æ»·¾³±äÁ¿ */ |
| run_command ("saveenv", 0); |
| } |
| |
| |
| sprintf (parm, "nand read %8x %08x %08x;", |
| CONFIG_SYS_LOAD_ADDR + SZ_16M, 0, CONFIG_SYS_BOOT_LEN); |
| |
| run_command (parm, 0); |
| |
| for (lseek = (CONFIG_SYS_LOAD_ADDR + SZ_16M + CONFIG_SYS_BOOT_LEN); |
| lseek > CONFIG_SYS_LOAD_ADDR + SZ_16M; |
| lseek -= CFG_ALLIGN_SIZE) |
| { |
| if ((((hd_boot_file *)lseek)->btMagic[0]==CSP_MAGIC3) && |
| (((hd_boot_file *)lseek)->btMagic[1]==CSP_MAGIC2) && |
| (((hd_boot_file *)lseek)->btMagic[2]==CSP_MAGIC1) && |
| (((hd_boot_file *)lseek)->btMagic[3]==CSP_MAGIC0)) |
| { |
| memset(cmdline, 0, sizeof(cmdline)); |
| sprintf(cmdline, "U-Boot %s %c%c%c%c%c%c%c%c%c%c%c%c%c%c ", ((hd_boot_file *)lseek)->btNumbers, |
| ((hd_boot_file *)lseek)->btCtime[0], |
| ((hd_boot_file *)lseek)->btCtime[1], |
| ((hd_boot_file *)lseek)->btCtime[2], |
| ((hd_boot_file *)lseek)->btCtime[3], |
| ((hd_boot_file *)lseek)->btCtime[5], |
| ((hd_boot_file *)lseek)->btCtime[6], |
| ((hd_boot_file *)lseek)->btCtime[8], |
| ((hd_boot_file *)lseek)->btCtime[9], |
| ((hd_boot_file *)lseek)->btCtime[11], |
| ((hd_boot_file *)lseek)->btCtime[12], |
| ((hd_boot_file *)lseek)->btCtime[14], |
| ((hd_boot_file *)lseek)->btCtime[15], |
| ((hd_boot_file *)lseek)->btCtime[17], |
| ((hd_boot_file *)lseek)->btCtime[18]); |
| |
| printf("cmdline=%s\n", cmdline); |
| break; |
| } |
| } |
| if(lseek>=(CONFIG_SYS_LOAD_ADDR + SZ_16M + CONFIG_SYS_BOOT_LEN)) |
| { |
| printf("error in do_settings!\n"); |
| return -1; |
| } |
| |
| sprintf (arg, "0x%lx ", search->result[select].entry-CSP_HEADER_LEN); |
| strcat (cmdline, arg); |
| if(search->total==1) |
| {/*Ë«°æ±¾µÄÒì³£Çé¿ö:Ö»Óа汾2*/ |
| if(search->result[select].entry <(nand_info[0].parts->soft0_offs + nand_info[0].parts->soft0_size)) |
| { |
| sprintf (arg, "0x%1x 0x%02x 0x%02x", 0, search->result[0].flags, search->result[1].flags); |
| } |
| else |
| { |
| sprintf (arg, "0x%1x 0x%02x 0x%02x", 1, search->result[1].flags, search->result[0].flags); |
| } |
| } |
| else |
| { |
| sprintf (arg, "0x%1x 0x%02x 0x%02x", select, search->result[0].flags, search->result[1].flags); |
| } |
| |
| strcat (cmdline, arg); |
| s = getenv ("versioninfo"); |
| if (((s!=NULL) && (strncmp(s, cmdline, strlen(cmdline))!=0)) || |
| (s==NULL)) |
| { |
| setenv ("versioninfo", cmdline); |
| bSaved = 1; |
| } |
| |
| |
| if (bSaved) /* ±£´æ»·¾³±äÁ¿ */ |
| { |
| run_command ("saveenv", 0); |
| } |
| |
| #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) |
| WATCHDOG_RESET(); |
| #endif |
| |
| return (0); |
| } |
| |
| #endif |
| #endif |
| |
| void do_env_restore(void) |
| { |
| setenv("ipaddr", "192.168.1.1"); |
| setenv("serverip", "192.168.1.100"); |
| return; |
| } |
| |
| U_BOOT_CMD( |
| downver, CONFIG_SYS_MAXARGS, 1, do_downver, |
| "upgrade software downloaded from TFTP server", |
| "name [...]\n" |
| " - allbins, upgrade allbins\n" |
| " - kernel, upgrade system software\n" |
| " - version [1|2], upgrade combined software\n" |
| ); |