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