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