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