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