source: SVN/rincon/u-boot/board/esd/common/auto_update.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 22 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 13.2 KB
Line 
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[CFG_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 = CFG_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[CFG_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        "autoupd - Automatically update images\n",
554        NULL
555);
556#endif /* CONFIG_AUTO_UPDATE */
Note: See TracBrowser for help on using the repository browser.