[U-Boot] common/update.c ITB update code refactoring (no new file)
Dvorkin Dmitry
dvorkin at tibbo.com
Thu Mar 10 07:16:34 CET 2011
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.
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_UPDATE)
+void update_itb (void);
+#endif /* CONFIG_UPDATE */
#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_UPDATE)
+ update_itb ();
+#endif /* CONFIG_UPDATE */
#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-10 09:12:25.546803490 +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_UPDATE) += update.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 2011-03-07 16:27:02.000000000 +0300
@@ -4,6 +4,10 @@
* Written by: Rafal Czubak <rcz at semihalf.com>
* Bartlomiej Sieka <tur at semihalf.com>
*
+ * (C) Copyright 2011 Tibbo Tech.
+ * Code refactoring, Cmd and Nand load/save features:
+ * Dvorkin Dmitry <dvorkin at tibbo.com>
+ *
* See file CREDITS for list of people who contributed to this
* project.
*
@@ -30,12 +34,13 @@
#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 <command.h>
+#if !defined(CONFIG_SYS_NO_FLASH)
#include <flash.h>
+#endif
+#if defined(CONFIG_CMD_NAND)
+#include <nand.h>
+#endif
#include <net.h>
#include <malloc.h>
@@ -43,16 +48,16 @@
#define UPDATE_FILE_ENV "updatefile"
/* set configuration defaults if needed */
-#ifndef CONFIG_UPDATE_LOAD_ADDR
-#define CONFIG_UPDATE_LOAD_ADDR 0x100000
+#ifndef CONFIG_UPDITB_LOAD_ADDR
+#define CONFIG_UPDITB_LOAD_ADDR 0x100000
#endif
-#ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
-#define CONFIG_UPDATE_TFTP_MSEC_MAX 100
+#ifndef CONFIG_UPDITB_TFTP_MSEC_MAX
+#define CONFIG_UPDITB_TFTP_MSEC_MAX 100
#endif
-#ifndef CONFIG_UPDATE_TFTP_CNT_MAX
-#define CONFIG_UPDATE_TFTP_CNT_MAX 0
+#ifndef CONFIG_UPDITB_TFTP_CNT_MAX
+#define CONFIG_UPDITB_TFTP_CNT_MAX 0
#endif
extern ulong TftpRRQTimeoutMSecs;
@@ -60,11 +65,91 @@
extern flash_info_t flash_info[];
extern ulong load_addr;
+extern int run_command (const char *cmd, int flag);
+
static uchar *saved_prot_info;
-static int update_load(char *filename, ulong msec_max, int cnt_max,
ulong addr)
+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;
@@ -109,6 +194,74 @@
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 <address> <file>' 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;
@@ -181,10 +334,11 @@
return 0;
}
-static int update_flash(ulong addr_source, ulong addr_first, ulong size)
+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;
@@ -221,6 +375,25 @@
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)
@@ -238,15 +411,23 @@
return 0;
}
-void update_tftp(void)
+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;
- printf("Auto-update from TFTP: ");
+ /* 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);
@@ -257,31 +438,68 @@
}
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_UPDATE_LOAD_ADDR;
-
+ addr = CONFIG_UPDITB_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;
+ 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) {
@@ -303,10 +521,33 @@
"aborting\n");
goto next_node;
}
- if (update_flash(update_addr, update_fladdr, update_size)) {
+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);
}
diff -urN a/include/configs/at91sam9m10g45ek.h
b/include/configs/at91sam9m10g45ek.h
--- a/include/configs/at91sam9m10g45ek.h 2011-02-28
15:46:10.000000000 +0300
+++ b/include/configs/at91sam9m10g45ek.h 2011-03-02
23:34:12.000000000 +0300
@@ -92,9 +92,11 @@
/* update feature */
#define CONFIG_FIT 1
#define CONFIG_OF_LIBFDT 1
-#define CONFIG_UPDATE_TFTP 1
-//#define CONFIG_UPDATE_CNT_MAX 0
-//#define CONFIG_UPDATE_MSEC_MAX 100
+#define CONFIG_UPDITB 1
+#define CONFIG_UPDITB_TFTP 1
+//#define CONFIG_UPDITB_CNT_MAX 0
+//#define CONFIG_UPDITB_MSEC_MAX 100
+#define CONFIG_UPDITB_LOAD_ADDR 0x72000000
/*
* Command line configuration.
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.
More information about the U-Boot
mailing list