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