uboot/board/esd/common/auto_update.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2003-2004
   3 * Gary Jennejohn, DENX Software Engineering, gj@denx.de.
   4 * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
   5 *
   6 * See file CREDITS for list of people who contributed to this
   7 * project.
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License as
  11 * published by the Free Software Foundation; either version 2 of
  12 * the License, or (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22 * MA 02111-1307 USA
  23 */
  24
  25#include <common.h>
  26
  27#include <command.h>
  28#include <image.h>
  29#include <asm/byteorder.h>
  30#if defined(CONFIG_NAND_LEGACY)
  31#include <linux/mtd/nand_legacy.h>
  32#endif
  33#include <fat.h>
  34#include <part.h>
  35
  36#include "auto_update.h"
  37
  38#ifdef CONFIG_AUTO_UPDATE
  39
  40#if !defined(CONFIG_CMD_FAT)
  41#error "must define CONFIG_CMD_FAT"
  42#endif
  43
  44extern au_image_t au_image[];
  45extern int N_AU_IMAGES;
  46
  47/* where to load files into memory */
  48#define LOAD_ADDR ((unsigned char *)0x100000)
  49#define MAX_LOADSZ 0x1c00000
  50
  51/* externals */
  52extern int fat_register_device(block_dev_desc_t *, int);
  53extern int file_fat_detectfs(void);
  54extern long file_fat_read(const char *, void *, unsigned long);
  55long do_fat_read (const char *filename, void *buffer,
  56                  unsigned long maxsize, int dols);
  57extern int flash_sect_erase(ulong, ulong);
  58extern int flash_sect_protect (int, ulong, ulong);
  59extern int flash_write (char *, ulong, ulong);
  60
  61#if defined(CONFIG_CMD_NAND) && defined(CONFIG_NAND_LEGACY)
  62/* references to names in cmd_nand.c */
  63#define NANDRW_READ     0x01
  64#define NANDRW_WRITE    0x00
  65#define NANDRW_JFFS2    0x02
  66#define NANDRW_JFFS2_SKIP       0x04
  67extern struct nand_chip nand_dev_desc[];
  68extern int nand_legacy_rw(struct nand_chip* nand, int cmd,
  69                          size_t start, size_t len,
  70                          size_t * retlen, u_char * buf);
  71extern int nand_legacy_erase(struct nand_chip* nand, size_t ofs,
  72                             size_t len, int clean);
  73#endif
  74
  75extern block_dev_desc_t ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE];
  76
  77int au_check_cksum_valid(int i, long nbytes)
  78{
  79        image_header_t *hdr;
  80
  81        hdr = (image_header_t *)LOAD_ADDR;
  82#if defined(CONFIG_FIT)
  83        if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) {
  84                puts ("Non legacy image format not supported\n");
  85                return -1;
  86        }
  87#endif
  88
  89        if ((au_image[i].type == AU_FIRMWARE) &&
  90            (au_image[i].size != image_get_data_size (hdr))) {
  91                printf ("Image %s has wrong size\n", au_image[i].name);
  92                return -1;
  93        }
  94
  95        if (nbytes != (image_get_image_size (hdr))) {
  96                printf ("Image %s bad total SIZE\n", au_image[i].name);
  97                return -1;
  98        }
  99
 100        /* check the data CRC */
 101        if (!image_check_dcrc (hdr)) {
 102                printf ("Image %s bad data checksum\n", au_image[i].name);
 103                return -1;
 104        }
 105        return 0;
 106}
 107
 108int au_check_header_valid(int i, long nbytes)
 109{
 110        image_header_t *hdr;
 111        unsigned long checksum;
 112
 113        hdr = (image_header_t *)LOAD_ADDR;
 114#if defined(CONFIG_FIT)
 115        if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) {
 116                puts ("Non legacy image format not supported\n");
 117                return -1;
 118        }
 119#endif
 120
 121        /* check the easy ones first */
 122        if (nbytes < image_get_header_size ()) {
 123                printf ("Image %s bad header SIZE\n", au_image[i].name);
 124                return -1;
 125        }
 126        if (!image_check_magic (hdr) || !image_check_arch (hdr, IH_ARCH_PPC)) {
 127                printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name);
 128                return -1;
 129        }
 130        if (!image_check_hcrc (hdr)) {
 131                printf ("Image %s bad header checksum\n", au_image[i].name);
 132                return -1;
 133        }
 134
 135        /* check the type - could do this all in one gigantic if() */
 136        if (((au_image[i].type & AU_TYPEMASK) == AU_FIRMWARE) &&
 137            !image_check_type (hdr, IH_TYPE_FIRMWARE)) {
 138                printf ("Image %s wrong type\n", au_image[i].name);
 139                return -1;
 140        }
 141        if (((au_image[i].type & AU_TYPEMASK) == AU_SCRIPT) &&
 142            !image_check_type (hdr, IH_TYPE_SCRIPT)) {
 143                printf ("Image %s wrong type\n", au_image[i].name);
 144                return -1;
 145        }
 146
 147        /* recycle checksum */
 148        checksum = image_get_data_size (hdr);
 149
 150        return 0;
 151}
 152
 153int au_do_update(int i, long sz)
 154{
 155        image_header_t *hdr;
 156        char *addr;
 157        long start, end;
 158        int off, rc;
 159        uint nbytes;
 160        int k;
 161#if defined(CONFIG_CMD_NAND) && defined(CONFIG_NAND_LEGACY)
 162        int total;
 163#endif
 164
 165        hdr = (image_header_t *)LOAD_ADDR;
 166#if defined(CONFIG_FIT)
 167        if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) {
 168                puts ("Non legacy image format not supported\n");
 169                return -1;
 170        }
 171#endif
 172
 173        switch (au_image[i].type & AU_TYPEMASK) {
 174        case AU_SCRIPT:
 175                printf("Executing script %s\n", au_image[i].name);
 176
 177                /* execute a script */
 178                if (image_check_type (hdr, IH_TYPE_SCRIPT)) {
 179                        addr = (char *)((char *)hdr + image_get_header_size ());
 180                        /* stick a NULL at the end of the script, otherwise */
 181                        /* parse_string_outer() runs off the end. */
 182                        addr[image_get_data_size (hdr)] = 0;
 183                        addr += 8;
 184
 185                        /*
 186                         * Replace cr/lf with ;
 187                         */
 188                        k = 0;
 189                        while (addr[k] != 0) {
 190                                if ((addr[k] == 10) || (addr[k] == 13)) {
 191                                        addr[k] = ';';
 192                                }
 193                                k++;
 194                        }
 195
 196                        run_command(addr, 0);
 197                        return 0;
 198                }
 199
 200                break;
 201
 202        case AU_FIRMWARE:
 203        case AU_NOR:
 204        case AU_NAND:
 205                start = au_image[i].start;
 206                end = au_image[i].start + au_image[i].size - 1;
 207
 208                /*
 209                 * do not update firmware when image is already in flash.
 210                 */
 211                if (au_image[i].type == AU_FIRMWARE) {
 212                        char *orig = (char*)start;
 213                        char *new  = (char *)((char *)hdr +
 214                                              image_get_header_size ());
 215                        nbytes = image_get_data_size (hdr);
 216
 217                        while (--nbytes) {
 218                                if (*orig++ != *new++) {
 219                                        break;
 220                                }
 221                        }
 222                        if (!nbytes) {
 223                                printf ("Skipping firmware update - "
 224                                        "images are identical\n");
 225                                break;
 226                        }
 227                }
 228
 229                /* unprotect the address range */
 230                if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) ||
 231                    (au_image[i].type == AU_FIRMWARE)) {
 232                        flash_sect_protect (0, start, end);
 233                }
 234
 235                /*
 236                 * erase the address range.
 237                 */
 238                if (au_image[i].type != AU_NAND) {
 239                        printf ("Updating NOR FLASH with image %s\n",
 240                                au_image[i].name);
 241                        debug ("flash_sect_erase(%lx, %lx);\n", start, end);
 242                        flash_sect_erase (start, end);
 243                } else {
 244#if defined(CONFIG_CMD_NAND) && defined(CONFIG_NAND_LEGACY)
 245                        printf ("Updating NAND FLASH with image %s\n",
 246                                au_image[i].name);
 247                        debug ("nand_legacy_erase(%lx, %lx);\n", start, end);
 248                        rc = nand_legacy_erase (nand_dev_desc, start,
 249                                                end - start + 1, 0);
 250                        debug ("nand_legacy_erase returned %x\n", rc);
 251#endif
 252                }
 253
 254                udelay(10000);
 255
 256                /* strip the header - except for the kernel and ramdisk */
 257                if (au_image[i].type != AU_FIRMWARE) {
 258                        addr = (char *)hdr;
 259                        off = image_get_header_size ();
 260                        nbytes = image_get_image_size (hdr);
 261                } else {
 262                        addr = (char *)((char *)hdr + image_get_header_size ());
 263                        off = 0;
 264                        nbytes = image_get_data_size (hdr);
 265                }
 266
 267                /*
 268                 * copy the data from RAM to FLASH
 269                 */
 270                if (au_image[i].type != AU_NAND) {
 271                        debug ("flash_write(%p, %lx, %x)\n",
 272                               addr, start, nbytes);
 273                        rc = flash_write ((char *)addr, start,
 274                                          (nbytes + 1) & ~1);
 275                } else {
 276#if defined(CONFIG_CMD_NAND) && defined(CONFIG_NAND_LEGACY)
 277                        debug ("nand_legacy_rw(%p, %lx, %x)\n",
 278                               addr, start, nbytes);
 279                        rc = nand_legacy_rw (nand_dev_desc,
 280                                             NANDRW_WRITE | NANDRW_JFFS2,
 281                                             start, nbytes, (size_t *)&total,
 282                                             (uchar *)addr);
 283                        debug ("nand_legacy_rw: ret=%x total=%d nbytes=%d\n",
 284                               rc, total, nbytes);
 285#else
 286                        rc = -1;
 287#endif
 288                }
 289                if (rc != 0) {
 290                        printf ("Flashing failed due to error %d\n", rc);
 291                        return -1;
 292                }
 293
 294                /*
 295                 * check the dcrc of the copy
 296                 */
 297                if (au_image[i].type != AU_NAND) {
 298                        rc = crc32 (0, (uchar *)(start + off),
 299                                    image_get_data_size (hdr));
 300                } else {
 301#if defined(CONFIG_CMD_NAND) && defined(CONFIG_NAND_LEGACY)
 302                        rc = nand_legacy_rw (nand_dev_desc,
 303                                             NANDRW_READ | NANDRW_JFFS2 |
 304                                             NANDRW_JFFS2_SKIP,
 305                                             start, nbytes, (size_t *)&total,
 306                                             (uchar *)addr);
 307                        rc = crc32 (0, (uchar *)(addr + off),
 308                                    image_get_data_size (hdr));
 309#endif
 310                }
 311                if (rc != image_get_dcrc (hdr)) {
 312                        printf ("Image %s Bad Data Checksum After COPY\n",
 313                                au_image[i].name);
 314                        return -1;
 315                }
 316
 317                /* protect the address range */
 318                /* this assumes that ONLY the firmware is protected! */
 319                if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) ||
 320                    (au_image[i].type == AU_FIRMWARE)) {
 321                        flash_sect_protect (1, start, end);
 322                }
 323
 324                break;
 325
 326        default:
 327                printf("Wrong image type selected!\n");
 328        }
 329
 330        return 0;
 331}
 332
 333static void process_macros (const char *input, char *output)
 334{
 335        char c, prev;
 336        const char *varname_start = NULL;
 337        int inputcnt  = strlen (input);
 338        int outputcnt = CONFIG_SYS_CBSIZE;
 339        int state = 0;  /* 0 = waiting for '$'  */
 340                        /* 1 = waiting for '(' or '{' */
 341                        /* 2 = waiting for ')' or '}' */
 342                        /* 3 = waiting for '''  */
 343#ifdef DEBUG_PARSER
 344        char *output_start = output;
 345
 346        printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n",
 347                strlen(input), input);
 348#endif
 349
 350        prev = '\0';                    /* previous character */
 351
 352        while (inputcnt && outputcnt) {
 353            c = *input++;
 354            inputcnt--;
 355
 356            if (state != 3) {
 357            /* remove one level of escape characters */
 358            if ((c == '\\') && (prev != '\\')) {
 359                if (inputcnt-- == 0)
 360                        break;
 361                prev = c;
 362                c = *input++;
 363            }
 364            }
 365
 366            switch (state) {
 367            case 0:                     /* Waiting for (unescaped) $ */
 368                if ((c == '\'') && (prev != '\\')) {
 369                        state = 3;
 370                        break;
 371                }
 372                if ((c == '$') && (prev != '\\')) {
 373                        state++;
 374                } else {
 375                        *(output++) = c;
 376                        outputcnt--;
 377                }
 378                break;
 379            case 1:                     /* Waiting for ( */
 380                if (c == '(' || c == '{') {
 381                        state++;
 382                        varname_start = input;
 383                } else {
 384                        state = 0;
 385                        *(output++) = '$';
 386                        outputcnt--;
 387
 388                        if (outputcnt) {
 389                                *(output++) = c;
 390                                outputcnt--;
 391                        }
 392                }
 393                break;
 394            case 2:                     /* Waiting for )        */
 395                if (c == ')' || c == '}') {
 396                        int i;
 397                        char envname[CONFIG_SYS_CBSIZE], *envval;
 398                        /* Varname # of chars */
 399                        int envcnt = input - varname_start - 1;
 400
 401                        /* Get the varname */
 402                        for (i = 0; i < envcnt; i++) {
 403                                envname[i] = varname_start[i];
 404                        }
 405                        envname[i] = 0;
 406
 407                        /* Get its value */
 408                        envval = getenv (envname);
 409
 410                        /* Copy into the line if it exists */
 411                        if (envval != NULL)
 412                                while ((*envval) && outputcnt) {
 413                                        *(output++) = *(envval++);
 414                                        outputcnt--;
 415                                }
 416                        /* Look for another '$' */
 417                        state = 0;
 418                }
 419                break;
 420            case 3:                     /* Waiting for '        */
 421                if ((c == '\'') && (prev != '\\')) {
 422                        state = 0;
 423                } else {
 424                        *(output++) = c;
 425                        outputcnt--;
 426                }
 427                break;
 428            }
 429            prev = c;
 430        }
 431
 432        if (outputcnt)
 433                *output = 0;
 434
 435#ifdef DEBUG_PARSER
 436        printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
 437                strlen (output_start), output_start);
 438#endif
 439}
 440
 441/*
 442 * this is called from board_init() after the hardware has been set up
 443 * and is usable. That seems like a good time to do this.
 444 * Right now the return value is ignored.
 445 */
 446int do_auto_update(void)
 447{
 448        block_dev_desc_t *stor_dev = NULL;
 449        long sz;
 450        int i, res, cnt, old_ctrlc, got_ctrlc;
 451        char buffer[32];
 452        char str[80];
 453        int n;
 454
 455        if  (ide_dev_desc[0].type != DEV_TYPE_UNKNOWN) {
 456                stor_dev = get_dev ("ide", 0);
 457                if (stor_dev == NULL) {
 458                        debug ("ide: unknown device\n");
 459                        return -1;
 460                }
 461        }
 462
 463        if (fat_register_device (stor_dev, 1) != 0) {
 464                debug ("Unable to register ide disk 0:1\n");
 465                return -1;
 466        }
 467
 468        /*
 469         * Check if magic file is present
 470         */
 471        if ((n = do_fat_read (AU_MAGIC_FILE, buffer,
 472                              sizeof(buffer), LS_NO)) <= 0) {
 473                debug ("No auto_update magic file (n=%d)\n", n);
 474                return -1;
 475        }
 476
 477#ifdef CONFIG_AUTO_UPDATE_SHOW
 478        board_auto_update_show (1);
 479#endif
 480        puts("\nAutoUpdate Disk detected! Trying to update system...\n");
 481
 482        /* make sure that we see CTRL-C and save the old state */
 483        old_ctrlc = disable_ctrlc (0);
 484
 485        /* just loop thru all the possible files */
 486        for (i = 0; i < N_AU_IMAGES; i++) {
 487                /*
 488                 * Try to expand the environment var in the fname
 489                 */
 490                process_macros (au_image[i].name, str);
 491                strcpy (au_image[i].name, str);
 492
 493                printf("Reading %s ...", au_image[i].name);
 494                /* just read the header */
 495                sz = do_fat_read (au_image[i].name, LOAD_ADDR,
 496                                  image_get_header_size (), LS_NO);
 497                debug ("read %s sz %ld hdr %d\n",
 498                        au_image[i].name, sz, image_get_header_size ());
 499                if (sz <= 0 || sz < image_get_header_size ()) {
 500                        puts(" not found\n");
 501                        continue;
 502                }
 503                if (au_check_header_valid (i, sz) < 0) {
 504                        puts(" header not valid\n");
 505                        continue;
 506                }
 507                sz = do_fat_read (au_image[i].name, LOAD_ADDR,
 508                                  MAX_LOADSZ, LS_NO);
 509                debug ("read %s sz %ld hdr %d\n",
 510                        au_image[i].name, sz, image_get_header_size ());
 511                if (sz <= 0 || sz <= image_get_header_size ()) {
 512                        puts(" not found\n");
 513                        continue;
 514                }
 515                if (au_check_cksum_valid (i, sz) < 0) {
 516                        puts(" checksum not valid\n");
 517                        continue;
 518                }
 519                puts(" done\n");
 520
 521                do {
 522                        res = au_do_update (i, sz);
 523                        /* let the user break out of the loop */
 524                        if (ctrlc() || had_ctrlc ()) {
 525                                clear_ctrlc ();
 526                                if (res < 0)
 527                                        got_ctrlc = 1;
 528                                break;
 529                        }
 530                        cnt++;
 531                } while (res < 0);
 532        }
 533
 534        /* restore the old state */
 535        disable_ctrlc (old_ctrlc);
 536
 537        puts("AutoUpdate finished\n\n");
 538#ifdef CONFIG_AUTO_UPDATE_SHOW
 539        board_auto_update_show (0);
 540#endif
 541
 542        return 0;
 543}
 544
 545int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 546{
 547        do_auto_update();
 548
 549        return 0;
 550}
 551U_BOOT_CMD(
 552        autoupd,        1,      1,      auto_update,
 553        "Automatically update images",
 554        NULL
 555);
 556#endif /* CONFIG_AUTO_UPDATE */
 557