blob: 49d6141a58fb1e1ae6afa79ed7346b8881f390e7 [file] [log] [blame]
/*
* (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"
);