From patchwork Mon Mar 7 14:20:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dvorkin Dmitry X-Patchwork-Id: 85749 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 8B37EB70FC for ; Tue, 8 Mar 2011 01:27:25 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 108832808B; Mon, 7 Mar 2011 15:27:22 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id TN3LzbN7sMPJ; Mon, 7 Mar 2011 15:27:21 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E908B28084; Mon, 7 Mar 2011 15:27:17 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B25C328084 for ; Mon, 7 Mar 2011 15:27:08 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id QeMAuf0kyJmb for ; Mon, 7 Mar 2011 15:27:02 +0100 (CET) X-Greylist: delayed 401 seconds by postgrey-1.27 at theia; Mon, 07 Mar 2011 15:27:00 CET X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from smtp.tibbo.com (smtp.tibbo.com [81.171.42.199]) by theia.denx.de (Postfix) with ESMTPS id 16E5328082 for ; Mon, 7 Mar 2011 15:27:00 +0100 (CET) Received: (qmail 17628 invoked by uid 508); 7 Mar 2011 17:24:56 +0300 Received: from dvhome.kansstel.ru (HELO ?10.1.1.20?) (79.171.10.83) by smtp.tibbo.com with SMTP; 7 Mar 2011 17:24:56 +0300 Message-ID: <4D74E9A1.1000800@tibbo.com> Date: Mon, 07 Mar 2011 17:20:17 +0300 From: Dvorkin Dmitry User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.12) Gecko/20101122 Mandriva/3.1.6-0.1mdv2010.1 (2010.1) Thunderbird/3.1.6 MIME-Version: 1.0 To: u-boot@lists.denx.de Subject: [U-Boot] common/update.c ITB update code refactoring X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de common/update.c used to update flash with ITB image. With this patch it can also use any templated nash commands to load and save blobs. Also it adds nand as possible target for update. Usage example: // to load itb from usb mass-storage device and save it into nand using nash commands setenv updatefile updateimage.itb setenv loadaddr 0x72000000 setenv upditb_load_method cmd setenv upditb_cmd_load_pre usb start setenv upditb_cmd_load fatload usb 0:1 {load_to} {file} setenv upditb_save_method cmd setenv upditb_cmd_save nand write {addr_src} {addr_dst} {img_size} // better way to do the same task: setenv updatefile updateimage.itb setenv loadaddr 0x72000000 setenv upditb_load_method cmd setenv upditb_cmd_load_pre usb start setenv upditb_cmd_load fatload usb 0:1 {load_to} {file} setenv upditb_save_method nand it directly calls write_nand_skip_bad() to save blobs. Better because of kernel image usually is not nand-page aligned, end-of-kernel blob does not fit into nand page borders, "nand" method trying to fix it. seems, common/upditb.c filname better fits it's perpose then common/update.c. and it sounds more general. old function names are changed also. diff -urN a/common/main.c b/common/main.c --- a/common/main.c 2010-09-29 01:20:55.000000000 +0400 +++ b/common/main.c 2011-03-02 23:34:12.000000000 +0300 @@ -56,9 +56,9 @@ extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); -#if defined(CONFIG_UPDATE_TFTP) -void update_tftp (void); -#endif /* CONFIG_UPDATE_TFTP */ +#if defined(CONFIG_UPDITB) +void update_itb (void); +#endif /* CONFIG_UPDITB */ #define MAX_DELAY_STOP_STR 32 @@ -365,9 +365,9 @@ } #endif /* CONFIG_PREBOOT */ -#if defined(CONFIG_UPDATE_TFTP) - update_tftp (); -#endif /* CONFIG_UPDATE_TFTP */ +#if defined(CONFIG_UPDITB) + update_itb (); +#endif /* CONFIG_UPDITB */ #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay"); diff -urN a/common/Makefile b/common/Makefile --- a/common/Makefile 2010-09-29 01:20:55.000000000 +0400 +++ b/common/Makefile 2011-03-02 23:34:12.000000000 +0300 @@ -164,7 +164,7 @@ COBJS-$(CONFIG_LCD) += lcd.o COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o -COBJS-$(CONFIG_UPDATE_TFTP) += update.o +COBJS-$(CONFIG_UPDITB) += upditb.o COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o diff -urN a/common/update.c b/common/update.c --- a/common/update.c 2011-02-28 15:46:10.000000000 +0300 +++ b/common/update.c 1970-01-01 03:00:00.000000000 +0300 @@ -1,315 +0,0 @@ -/* - * (C) Copyright 2008 Semihalf - * - * Written by: Rafal Czubak - * Bartlomiej Sieka - * - * 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 - * - */ - -#include - -#if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT)) -#error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature" -#endif - -#if defined(CONFIG_SYS_NO_FLASH) -#error "CONFIG_SYS_NO_FLASH defined, but FLASH is required for auto-update feature" -#endif - -#include -#include -#include -#include - -/* env variable holding the location of the update file */ -#define UPDATE_FILE_ENV "updatefile" - -/* set configuration defaults if needed */ -#ifndef CONFIG_UPDATE_LOAD_ADDR -#define CONFIG_UPDATE_LOAD_ADDR 0x100000 -#endif - -#ifndef CONFIG_UPDATE_TFTP_MSEC_MAX -#define CONFIG_UPDATE_TFTP_MSEC_MAX 100 -#endif - -#ifndef CONFIG_UPDATE_TFTP_CNT_MAX -#define CONFIG_UPDATE_TFTP_CNT_MAX 0 -#endif - -extern ulong TftpRRQTimeoutMSecs; -extern int TftpRRQTimeoutCountMax; -extern flash_info_t flash_info[]; -extern ulong load_addr; - -static uchar *saved_prot_info; - -static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr) -{ - int size, rv; - ulong saved_timeout_msecs; - int saved_timeout_count; - char *saved_netretry, *saved_bootfile; - - rv = 0; - /* save used globals and env variable */ - saved_timeout_msecs = TftpRRQTimeoutMSecs; - saved_timeout_count = TftpRRQTimeoutCountMax; - saved_netretry = strdup(getenv("netretry")); - saved_bootfile = strdup(BootFile); - - /* set timeouts for auto-update */ - TftpRRQTimeoutMSecs = msec_max; - TftpRRQTimeoutCountMax = cnt_max; - - /* we don't want to retry the connection if errors occur */ - setenv("netretry", "no"); - - /* download the update file */ - load_addr = addr; - copy_filename(BootFile, filename, sizeof(BootFile)); - size = NetLoop(TFTP); - - if (size < 0) - rv = 1; - else if (size > 0) - flush_cache(addr, size); - - /* restore changed globals and env variable */ - TftpRRQTimeoutMSecs = saved_timeout_msecs; - TftpRRQTimeoutCountMax = saved_timeout_count; - - setenv("netretry", saved_netretry); - if (saved_netretry != NULL) - free(saved_netretry); - - if (saved_bootfile != NULL) { - copy_filename(BootFile, saved_bootfile, sizeof(BootFile)); - free(saved_bootfile); - } - - return rv; -} - -static int update_flash_protect(int prot, ulong addr_first, ulong addr_last) -{ - uchar *sp_info_ptr; - ulong s; - int i, bank, cnt; - flash_info_t *info; - - sp_info_ptr = NULL; - - if (prot == 0) { - saved_prot_info = - calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1); - if (!saved_prot_info) - return 1; - } - - for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { - cnt = 0; - info = &flash_info[bank]; - - /* Nothing to do if the bank doesn't exist */ - if (info->sector_count == 0) - return 0; - - /* Point to current bank protection information */ - sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT); - - /* - * Adjust addr_first or addr_last if we are on bank boundary. - * Address space between banks must be continuous for other - * flash functions (like flash_sect_erase or flash_write) to - * succeed. Banks must also be numbered in correct order, - * according to increasing addresses. - */ - if (addr_last > info->start[0] + info->size - 1) - addr_last = info->start[0] + info->size - 1; - if (addr_first < info->start[0]) - addr_first = info->start[0]; - - for (i = 0; i < info->sector_count; i++) { - /* Save current information about protected sectors */ - if (prot == 0) { - s = info->start[i]; - if ((s >= addr_first) && (s <= addr_last)) - sp_info_ptr[i] = info->protect[i]; - - } - - /* Protect/unprotect sectors */ - if (sp_info_ptr[i] == 1) { -#if defined(CONFIG_SYS_FLASH_PROTECTION) - if (flash_real_protect(info, i, prot)) - return 1; -#else - info->protect[i] = prot; -#endif - cnt++; - } - } - - if (cnt) { - printf("%sProtected %d sectors\n", - prot ? "": "Un-", cnt); - } - } - - if((prot == 1) && saved_prot_info) - free(saved_prot_info); - - return 0; -} - -static int update_flash(ulong addr_source, ulong addr_first, ulong size) -{ - ulong addr_last = addr_first + size - 1; - - /* round last address to the sector boundary */ - if (flash_sect_roundb(&addr_last) > 0) - return 1; - - if (addr_first >= addr_last) { - printf("Error: end address exceeds addressing space\n"); - return 1; - } - - /* remove protection on processed sectors */ - if (update_flash_protect(0, addr_first, addr_last) > 0) { - printf("Error: could not unprotect flash sectors\n"); - return 1; - } - - printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last); - if (flash_sect_erase(addr_first, addr_last) > 0) { - printf("Error: could not erase flash\n"); - return 1; - } - - printf("Copying to flash..."); - if (flash_write((char *)addr_source, addr_first, size) > 0) { - printf("Error: could not copy to flash\n"); - return 1; - } - printf("done\n"); - - /* enable protection on processed sectors */ - if (update_flash_protect(1, addr_first, addr_last) > 0) { - printf("Error: could not protect flash sectors\n"); - return 1; - } - - return 0; -} - -static int update_fit_getparams(const void *fit, int noffset, ulong *addr, - ulong *fladdr, ulong *size) -{ - const void *data; - - if (fit_image_get_data(fit, noffset, &data, (size_t *)size)) - return 1; - - if (fit_image_get_load(fit, noffset, (ulong *)fladdr)) - return 1; - - *addr = (ulong)data; - - return 0; -} - -void update_tftp(void) -{ - char *filename, *env_addr; - int images_noffset, ndepth, noffset; - ulong update_addr, update_fladdr, update_size; - ulong addr; - void *fit; - - printf("Auto-update from TFTP: "); - - /* get the file name of the update file */ - filename = getenv(UPDATE_FILE_ENV); - if (filename == NULL) { - printf("failed, env. variable '%s' not found\n", - UPDATE_FILE_ENV); - return; - } - - printf("trying update file '%s'\n", filename); - - /* get load address of downloaded update file */ - if ((env_addr = getenv("loadaddr")) != NULL) - addr = simple_strtoul(env_addr, NULL, 16); - else - addr = CONFIG_UPDATE_LOAD_ADDR; - - - if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX, - CONFIG_UPDATE_TFTP_CNT_MAX, addr)) { - printf("Can't load update file, aborting auto-update\n"); - return; - } - - fit = (void *)addr; - - if (!fit_check_format((void *)fit)) { - printf("Bad FIT format of the update file, aborting " - "auto-update\n"); - return; - } - - /* process updates */ - images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); - - ndepth = 0; - noffset = fdt_next_node(fit, images_noffset, &ndepth); - while (noffset >= 0 && ndepth > 0) { - if (ndepth != 1) - goto next_node; - - printf("Processing update '%s' :", - fit_get_name(fit, noffset, NULL)); - - if (!fit_image_check_hashes(fit, noffset)) { - printf("Error: invalid update hash, aborting\n"); - goto next_node; - } - - printf("\n"); - if (update_fit_getparams(fit, noffset, &update_addr, - &update_fladdr, &update_size)) { - printf("Error: can't get update parameteres, " - "aborting\n"); - goto next_node; - } - if (update_flash(update_addr, update_fladdr, update_size)) { - printf("Error: can't flash update (%ld %ld %ld), aborting\n", update_addr, update_fladdr, update_size); - goto next_node; - } -next_node: - noffset = fdt_next_node(fit, noffset, &ndepth); - } - - return; -} diff -urN a/common/upditb.c b/common/upditb.c --- a/common/upditb.c 1970-01-01 03:00:00.000000000 +0300 +++ b/common/upditb.c 2011-03-07 16:27:02.000000000 +0300 @@ -0,0 +1,556 @@ +/* + * (C) Copyright 2008 Semihalf + * + * Written by: Rafal Czubak + * Bartlomiej Sieka + * + * (C) Copyright 2011 Tibbo Tech. + * Code refactoring, Cmd and Nand load/save features: + * Dvorkin Dmitry + * + * 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 + * + */ + +#include + +#if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT)) +#error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature" +#endif + +#include +#if !defined(CONFIG_SYS_NO_FLASH) +#include +#endif +#if defined(CONFIG_CMD_NAND) +#include +#endif +#include +#include + +/* env variable holding the location of the update file */ +#define UPDATE_FILE_ENV "updatefile" + +/* set configuration defaults if needed */ +#ifndef CONFIG_UPDITB_LOAD_ADDR +#define CONFIG_UPDITB_LOAD_ADDR 0x100000 +#endif + +#ifndef CONFIG_UPDITB_TFTP_MSEC_MAX +#define CONFIG_UPDITB_TFTP_MSEC_MAX 100 +#endif + +#ifndef CONFIG_UPDITB_TFTP_CNT_MAX +#define CONFIG_UPDITB_TFTP_CNT_MAX 0 +#endif + +extern ulong TftpRRQTimeoutMSecs; +extern int TftpRRQTimeoutCountMax; +extern flash_info_t flash_info[]; +extern ulong load_addr; + +extern int run_command (const char *cmd, int flag); + +static uchar *saved_prot_info; + +enum XLAT_ST { + XLAT_ST_D, /* default */ + XLAT_ST_S, /* skip \ */ + XLAT_ST_B, /* begin attr name */ + XLAT_ST_A, /* in attr name */ + XLAT_ST_s, /* skip \} in attr name */ + XLAT_ST_E, /* end attr name */ +}; + +enum XLAT_CT { + XLAT_CT_DEF, + XLAT_CT_BKS, + XLAT_CT_BEG, + XLAT_CT_END, +}; + +enum XLAT_ST xlat_st_tbl[ 6][ 4] = { + // def \\ { } + { XLAT_ST_D, XLAT_ST_S, XLAT_ST_B, XLAT_ST_D }, // _ST_D + { XLAT_ST_D, XLAT_ST_D, XLAT_ST_D, XLAT_ST_D }, // _ST_S + { XLAT_ST_A, XLAT_ST_A, XLAT_ST_A, XLAT_ST_E }, // _ST_B + { XLAT_ST_A, XLAT_ST_s, XLAT_ST_A, XLAT_ST_E }, // _ST_A + { XLAT_ST_A, XLAT_ST_A, XLAT_ST_A, XLAT_ST_A }, // _ST_s + { XLAT_ST_D, XLAT_ST_S, XLAT_ST_B, XLAT_ST_D }, // _ST_E +}; + +typedef char *( *xlat_cfpt)( void *_data, char *_as, ulong _al, ulong *_rlen); + +static int Xlat_R( const char *_i, ulong _il, char *_o, ulong _ol, + xlat_cfpt _cfp, void *_data) { + ulong i = -1, oi = 0; + ulong rlen, ret = 0; + char *tks; + ulong tkl; + char *repl_av = NULL; + unsigned char c; + enum XLAT_CT ctype; + enum XLAT_ST curst = XLAT_ST_D; + + tks = NULL; tkl = 0; + while ( ++i < _il && ( c = _i[ i]) != '\0') { +//printf( "x:%d\n", i); + ctype = XLAT_CT_DEF; + if ( c == '\\') ctype = XLAT_CT_BKS; + if ( c == '{' ) ctype = XLAT_CT_BEG; + if ( c == '}' ) ctype = XLAT_CT_END; + curst = xlat_st_tbl[ curst][ ctype]; + switch ( curst) { + case XLAT_ST_s: + case XLAT_ST_S: break; + case XLAT_ST_D: if ( _o) _o[ oi++] = c; break; + case XLAT_ST_B: tks = ( _i + i + 1); tkl = 0; break; + case XLAT_ST_A: tkl++; break; + case XLAT_ST_E: +// printf( "AVP:%s\n", tmp_attr); + // macro name ended + ret++; + // if output buffer == NULL - return number of potential subs + if ( !_o) break; + repl_av = NULL; rlen = 0; + if ( _cfp) repl_av = _cfp( _data, tks, tkl, &rlen); + // actually replace + if ( repl_av != NULL) { memcpy( _o + oi, repl_av, rlen); oi += rlen; } + // if replace to NULL + if ( repl_av == NULL && rlen > 0) break; + // if no replace found - copy {text} to output - safe for future + if ( repl_av == NULL && rlen < 1) { + _o[ oi++] = '{'; + memcpy( _o + oi, tks, tkl); oi += tkl; + _o[ oi++] = '}'; } + break; + } // end of switch + if ( tkl >= _ol) return( ret); + } + return( ret); } + +static int update_load_tftp(char *filename, ulong addr) +{ + int size, rv; + ulong msec_max = CONFIG_UPDITB_TFTP_MSEC_MAX; + int cnt_max = CONFIG_UPDITB_TFTP_CNT_MAX; + ulong saved_timeout_msecs; + int saved_timeout_count; + char *saved_netretry, *saved_bootfile; + + rv = 0; + /* save used globals and env variable */ + saved_timeout_msecs = TftpRRQTimeoutMSecs; + saved_timeout_count = TftpRRQTimeoutCountMax; + saved_netretry = strdup(getenv("netretry")); + saved_bootfile = strdup(BootFile); + + /* set timeouts for auto-update */ + TftpRRQTimeoutMSecs = msec_max; + TftpRRQTimeoutCountMax = cnt_max; + + /* we don't want to retry the connection if errors occur */ + setenv("netretry", "no"); + + /* download the update file */ + load_addr = addr; + copy_filename(BootFile, filename, sizeof(BootFile)); + size = NetLoop(TFTP); + + if (size < 0) + rv = 1; + else if (size > 0) + flush_cache(addr, size); + + /* restore changed globals and env variable */ + TftpRRQTimeoutMSecs = saved_timeout_msecs; + TftpRRQTimeoutCountMax = saved_timeout_count; + + setenv("netretry", saved_netretry); + if (saved_netretry != NULL) + free(saved_netretry); + + if (saved_bootfile != NULL) { + copy_filename(BootFile, saved_bootfile, sizeof(BootFile)); + free(saved_bootfile); + } + + return rv; +} + +typedef struct Xlate_load_T { + char *file; + ulong load_to; +} Xlate_load_t; + +char *Xlate_load( void *_data, char *_as, ulong _al, ulong *_rlen) { + Xlate_load_t *Xdp = ( Xlate_load_t *)_data; + char xs[ 64]; + memset( xs, 0, 64); + if ( _al == 4 && memcmp( _as, "file", 4) == 0) sprintf( xs, "%s", Xdp->file); + if ( _al == 7 && memcmp( _as, "load_to", 7) == 0) sprintf( xs, "0x%08x", Xdp->load_to); + *_rlen = strlen( xs); + return( xs); } + +static int update_load_cmd( char *_file, ulong _addr) { + char *cmd; + char cmdx[ 1024]; + Xlate_load_t Xd = { .file = _file, .load_to = _addr }; + if ( ( cmd = getenv( "upditb_cmd_load_pre")) != NULL) { + memset( cmdx, 0, 1024); + Xlat_R( cmd, strlen( cmd), cmdx, 1024, Xlate_load, &Xd); + printf( "Preload cmd template:%s\n", cmd); + printf( "Xlated to:%s\n", cmdx); + /* prepare for loading into RAM, 'usb start' for ex. */ + if ( run_command( cmdx, 0) == -1) return( 1); + } + /* load to RAM. 'fatload usb 0:1
' for ex. */ + if ( ( cmd = getenv( "upditb_cmd_load")) != NULL) { + memset( cmdx, 0, 1024); + Xlat_R( cmd, strlen( cmd), cmdx, 1024, Xlate_load, &Xd); + printf( "Load cmd template:%s\n", cmd); + printf( "Xlated to:%s\n", cmdx); + /* prepare for loading into RAM, 'usb start' for ex. */ + if ( run_command( cmdx, 0) == -1) return( 1); + } + return( 0); } + +typedef struct Xlate_flash_T { + ulong a_src; + ulong a_dst; + ulong size; +} Xlate_flash_t; + +char *Xlate_flash( void *_data, char *_as, ulong _al, ulong *_rlen) { + Xlate_flash_t *Xdp = ( Xlate_flash_t *)_data; + char xs[ 64]; + memset( xs, 0, 64); + if ( _al == 8 && memcmp( _as, "addr_src", 8) == 0) sprintf( xs, "0x%08x", Xdp->a_src); + if ( _al == 8 && memcmp( _as, "addr_dst", 8) == 0) sprintf( xs, "0x%08x", Xdp->a_dst); + if ( _al == 8 && memcmp( _as, "img_size", 8) == 0) sprintf( xs, "0x%08x", Xdp->size); + *_rlen = strlen( xs); + return( xs); } + +static int update_s_cmd( ulong _addr_source, ulong _addr_first, ulong _size) { + char *cmdc; + char cmdcx[ 1024]; + Xlate_flash_t Xd = { .a_src = _addr_source, .a_dst = _addr_first, .size = _size }; + printf( "%s()\n", __FUNCTION__); + if ( ( cmdc = getenv( "upditb_cmd_save")) == NULL) return( 1); + memset( cmdcx, 0, 1024); + Xlat_R( cmdc, strlen( cmdc), cmdcx, 1024, Xlate_flash, &Xd); + printf( "Save cmd template:%s\n", cmdc); + printf( "Xlated to:%s\n", cmdcx); + /* save to target, nand write {addr_src} {addr_dst} {img_size} for ex. */ + if ( run_command( cmdcx, 0) == -1) return( 1); + return( 0); } + +#if !defined(CONFIG_SYS_NO_FLASH) +static int update_flash_protect(int prot, ulong addr_first, ulong addr_last) +{ + uchar *sp_info_ptr; + ulong s; + int i, bank, cnt; + flash_info_t *info; + + sp_info_ptr = NULL; + + if (prot == 0) { + saved_prot_info = + calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1); + if (!saved_prot_info) + return 1; + } + + for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { + cnt = 0; + info = &flash_info[bank]; + + /* Nothing to do if the bank doesn't exist */ + if (info->sector_count == 0) + return 0; + + /* Point to current bank protection information */ + sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT); + + /* + * Adjust addr_first or addr_last if we are on bank boundary. + * Address space between banks must be continuous for other + * flash functions (like flash_sect_erase or flash_write) to + * succeed. Banks must also be numbered in correct order, + * according to increasing addresses. + */ + if (addr_last > info->start[0] + info->size - 1) + addr_last = info->start[0] + info->size - 1; + if (addr_first < info->start[0]) + addr_first = info->start[0]; + + for (i = 0; i < info->sector_count; i++) { + /* Save current information about protected sectors */ + if (prot == 0) { + s = info->start[i]; + if ((s >= addr_first) && (s <= addr_last)) + sp_info_ptr[i] = info->protect[i]; + + } + + /* Protect/unprotect sectors */ + if (sp_info_ptr[i] == 1) { +#if defined(CONFIG_SYS_FLASH_PROTECTION) + if (flash_real_protect(info, i, prot)) + return 1; +#else + info->protect[i] = prot; +#endif + cnt++; + } + } + + if (cnt) { + printf("%sProtected %d sectors\n", + prot ? "": "Un-", cnt); + } + } + + if((prot == 1) && saved_prot_info) + free(saved_prot_info); + + return 0; +} + +static int update_s_flash(ulong addr_source, ulong addr_first, ulong size) +{ + ulong addr_last = addr_first + size - 1; + + printf( "%s()\n", __FUNCTION__); + /* round last address to the sector boundary */ + if (flash_sect_roundb(&addr_last) > 0) + return 1; + + if (addr_first >= addr_last) { + printf("Error: end address exceeds addressing space\n"); + return 1; + } + + /* remove protection on processed sectors */ + if (update_flash_protect(0, addr_first, addr_last) > 0) { + printf("Error: could not unprotect flash sectors\n"); + return 1; + } + + printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last); + if (flash_sect_erase(addr_first, addr_last) > 0) { + printf("Error: could not erase flash\n"); + return 1; + } + + printf("Copying to flash..."); + if (flash_write((char *)addr_source, addr_first, size) > 0) { + printf("Error: could not copy to flash\n"); + return 1; + } + printf("done\n"); + + /* enable protection on processed sectors */ + if (update_flash_protect(1, addr_first, addr_last) > 0) { + printf("Error: could not protect flash sectors\n"); + return 1; + } + + return 0; +} +#endif + +#if defined(CONFIG_CMD_NAND) +static int update_s_nand( ulong _a_src, ulong _a_dst, size_t _size) +{ + int err; + size_t len = _size; + size_t tl; + tl = nand_info[ 0].writesize; + printf( "%s()\n", __FUNCTION__); + if ( ( _size % tl) != 0) { + printf( "padding %d with %d bytes\n", _size, ( tl - ( _size % tl))); + len = _size += ( tl - ( _size % tl)); + printf( "new size is %d bytes\n", _size); + } + err = nand_write_skip_bad( &nand_info[ 0], _a_dst, &len, _a_src); + if ( err != 0) return( 1); + return( 0); } +#endif + +static int update_fit_getparams(const void *fit, int noffset, ulong *addr, + ulong *fladdr, ulong *size) +{ + const void *data; + + if (fit_image_get_data(fit, noffset, &data, (size_t *)size)) + return 1; + + if (fit_image_get_load(fit, noffset, (ulong *)fladdr)) + return 1; + + *addr = (ulong)data; + + return 0; +} + +void update_itb(void) +{ + char *filename, *env_addr; + char *method_load, *method_save, *ts; + int images_noffset, ndepth, noffset; + ulong update_addr, update_fladdr, update_size; + ulong addr; + void *fit; + int err, sl; + + /* update method: tftp or something else */ + ts = method_load = getenv( "upditb_load_method"); + if ( method_load == NULL) method_load = "none"; + printf( "Auto-update ITB load method:%s\n", method_load); + if ( ts == NULL) return; + method_save = getenv( "upditb_save_method"); + if ( method_save == NULL) method_save = "flash"; + + /* get the file name of the update file */ + filename = getenv(UPDATE_FILE_ENV); + if (filename == NULL) { + printf("failed, env. variable '%s' not found\n", + UPDATE_FILE_ENV); + return; + } + + printf("trying update file '%s'\n", filename); +#ifdef CONFIG_LCD + lcd_printf( "Loading auto-update file '%s'...", filename); +#endif + + /* get load address of downloaded update file */ + if ((env_addr = getenv("loadaddr")) != NULL) + addr = simple_strtoul(env_addr, NULL, 16); + else + addr = CONFIG_UPDITB_LOAD_ADDR; + + err = -1; + sl = strlen( method_load); + if ( sl == 4 && strcmp( method_load, "tftp") == 0) err = update_load_tftp( filename, addr); + if ( sl == 3 && strcmp( method_load, "cmd" ) == 0) err = update_load_cmd( filename, addr); + switch ( err) { + case -1: +#ifdef CONFIG_LCD + lcd_printf( "ERR-1\n"); +#endif + printf( "No such method '%s', aborting auto-update\n", method_load); + return; + break; + case 0: /* it's OK */ +#ifdef CONFIG_LCD + lcd_printf( "OK\n"); +#endif + break; + default: +#ifdef CONFIG_LCD + lcd_printf( "ERR\n"); +#endif + printf( "Can't load update file, aborting auto-update\n"); + return; + break; + } + +#ifdef CONFIG_LCD + lcd_printf( "Auto-update file is loaded, checking..."); +#endif + fit = (void *)addr; + + if (!fit_check_format((void *)fit)) { + printf("Bad FIT format of the update file, aborting " + "auto-update\n"); +#ifdef CONFIG_LCD + lcd_printf( "ERR\n"); +#endif + return; + } +#ifdef CONFIG_LCD + lcd_printf( "OK\n"); +#endif + + /* process updates */ + images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); + +#ifdef CONFIG_LCD + err = fit_get_desc( fit, 0, &ts); + if ( err) ts = "(no description)"; + lcd_printf( "Processing %s...\n", ts); +#endif +fit_print_contents( (void *)fit); + ndepth = 0; + noffset = fdt_next_node(fit, images_noffset, &ndepth); + while (noffset >= 0 && ndepth > 0) { + if (ndepth != 1) + goto next_node; + + printf("Processing update '%s' :", + fit_get_name(fit, noffset, NULL)); + + if (!fit_image_check_hashes(fit, noffset)) { + printf("Error: invalid update hash, aborting\n"); + goto next_node; + } + + printf("\n"); + if (update_fit_getparams(fit, noffset, &update_addr, + &update_fladdr, &update_size)) { + printf("Error: can't get update parameteres, " + "aborting\n"); + goto next_node; + } +fit_image_print( fit, noffset, ""); +#ifdef CONFIG_LCD + err = fit_get_desc( fit, noffset, &ts); + if ( err) ts = "(no description)"; + lcd_printf( "Flashing %s...", ts); +#endif + sl = strlen( method_save); + err = -1; +#if !defined(CONFIG_SYS_NO_FLASH) + if ( sl == 5 && strcmp( method_save, "flash") == 0) err = update_s_flash(update_addr, update_fladdr, update_size); +#endif + if ( sl == 3 && strcmp( method_save, "cmd" ) == 0) err = update_s_cmd( update_addr, update_fladdr, update_size); +#if defined(CONFIG_CMD_NAND) + if ( sl == 4 && strcmp( method_save, "nand") == 0) err = update_s_nand(update_addr, update_fladdr, update_size); +#endif + /* fallback if method not found */ + if ( err == -1) err = update_s_flash(update_addr, update_fladdr, update_size); + if ( err) { + printf("Error: can't flash update (%ld %ld %ld), aborting\n", update_addr, update_fladdr, update_size); +#ifdef CONFIG_LCD + lcd_printf( "ERR\n"); +#endif + goto next_node; + } +#ifdef CONFIG_LCD + lcd_printf( "OK\n"); +#endif +next_node: + noffset = fdt_next_node(fit, noffset, &ndepth); + } + + return; +} diff -urN a/README b/README --- a/README 2010-09-29 01:20:55.000000000 +0400 +++ b/README 2011-03-02 23:34:12.000000000 +0300 @@ -2108,10 +2108,11 @@ -150 common/cmd_nand.c Incorrect FIT image format 151 common/cmd_nand.c FIT image format OK -- Automatic software updates via TFTP server - CONFIG_UPDATE_TFTP - CONFIG_UPDATE_TFTP_CNT_MAX - CONFIG_UPDATE_TFTP_MSEC_MAX +- Automatic software updates via ITB structure + CONFIG_UPDITB + CONFIG_UPDITB_TFTP + CONFIG_UPDITB_TFTP_CNT_MAX + CONFIG_UPDITB_TFTP_MSEC_MAX These options enable and control the auto-update feature; for a more detailed description refer to doc/README.update.