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