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