blob: 5a70176fade91f0c2352f46463a6b4cac6610534 [file] [log] [blame]
stroese0621f6f2004-12-16 18:43:13 +00001/*
2 * (C) Copyright 2003-2004
3 * Gary Jennejohn, DENX Software Engineering, gj@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>
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010026
27#ifndef CFG_NAND_LEGACY
28#error CFG_NAND_LEGACY not defined in a file using the legacy NAND support!
29#endif
30
stroese0621f6f2004-12-16 18:43:13 +000031#include <command.h>
32#include <image.h>
33#include <asm/byteorder.h>
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010034#include <linux/mtd/nand_legacy.h>
stroese0621f6f2004-12-16 18:43:13 +000035#include <fat.h>
36
37#include "auto_update.h"
38
39#ifdef CONFIG_AUTO_UPDATE
40
41#if !(CONFIG_COMMANDS & CFG_CMD_FAT)
42#error "must define CFG_CMD_FAT"
43#endif
44
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010045
46
47
stroese0621f6f2004-12-16 18:43:13 +000048extern au_image_t au_image[];
49extern int N_AU_IMAGES;
50
51#define AU_DEBUG
52#undef AU_DEBUG
53
54#undef debug
55#ifdef AU_DEBUG
56#define debug(fmt,args...) printf (fmt ,##args)
57#else
58#define debug(fmt,args...)
59#endif /* AU_DEBUG */
60
61
62#define LOAD_ADDR ((unsigned char *)0x100000) /* where to load files into memory */
63#define MAX_LOADSZ 0x1e00000
64
65/* externals */
66extern int fat_register_device(block_dev_desc_t *, int);
67extern int file_fat_detectfs(void);
68extern long file_fat_read(const char *, void *, unsigned long);
69long do_fat_read (const char *filename, void *buffer, unsigned long maxsize, int dols);
70#ifdef CONFIG_VFD
71extern int trab_vfd (ulong);
72extern int transfer_pic(unsigned char, unsigned char *, int, int);
73#endif
74extern int flash_sect_erase(ulong, ulong);
75extern int flash_sect_protect (int, ulong, ulong);
Stefan Roesea5477752005-10-20 16:39:16 +020076extern int flash_write (char *, ulong, ulong);
stroese0621f6f2004-12-16 18:43:13 +000077/* change char* to void* to shutup the compiler */
78extern block_dev_desc_t *get_dev (char*, int);
79
80#if (CONFIG_COMMANDS & CFG_CMD_NAND)
81/* references to names in cmd_nand.c */
82#define NANDRW_READ 0x01
83#define NANDRW_WRITE 0x00
84#define NANDRW_JFFS2 0x02
85#define NANDRW_JFFS2_SKIP 0x04
86extern struct nand_chip nand_dev_desc[];
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010087extern int nand_legacy_rw(struct nand_chip* nand, int cmd, size_t start, size_t len,
stroese0621f6f2004-12-16 18:43:13 +000088 size_t * retlen, u_char * buf);
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010089extern int nand_legacy_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
stroese0621f6f2004-12-16 18:43:13 +000090#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
91
92extern block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
93
94
95int au_check_cksum_valid(int i, long nbytes)
96{
97 image_header_t *hdr;
98 unsigned long checksum;
99
100 hdr = (image_header_t *)LOAD_ADDR;
101
102 if ((au_image[i].type == AU_FIRMWARE) && (au_image[i].size != ntohl(hdr->ih_size))) {
103 printf ("Image %s has wrong size\n", au_image[i].name);
104 return -1;
105 }
106
107 if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) {
108 printf ("Image %s bad total SIZE\n", au_image[i].name);
109 return -1;
110 }
111 /* check the data CRC */
112 checksum = ntohl(hdr->ih_dcrc);
113
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200114 if (crc32 (0, (uchar *)(LOAD_ADDR + sizeof(*hdr)), ntohl(hdr->ih_size))
stroese0621f6f2004-12-16 18:43:13 +0000115 != checksum) {
116 printf ("Image %s bad data checksum\n", au_image[i].name);
117 return -1;
118 }
119 return 0;
120}
121
122
123int au_check_header_valid(int i, long nbytes)
124{
125 image_header_t *hdr;
126 unsigned long checksum;
127
128 hdr = (image_header_t *)LOAD_ADDR;
129 /* check the easy ones first */
130#undef CHECK_VALID_DEBUG
131#ifdef CHECK_VALID_DEBUG
132 printf("magic %#x %#x ", ntohl(hdr->ih_magic), IH_MAGIC);
133 printf("arch %#x %#x ", hdr->ih_arch, IH_CPU_PPC);
134 printf("size %#x %#lx ", ntohl(hdr->ih_size), nbytes);
135 printf("type %#x %#x ", hdr->ih_type, IH_TYPE_KERNEL);
136#endif
137 if (nbytes < sizeof(*hdr))
138 {
139 printf ("Image %s bad header SIZE\n", au_image[i].name);
140 return -1;
141 }
142 if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_CPU_PPC)
143 {
144 printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name);
145 return -1;
146 }
147 /* check the hdr CRC */
148 checksum = ntohl(hdr->ih_hcrc);
149 hdr->ih_hcrc = 0;
150
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200151 if (crc32 (0, (uchar *)hdr, sizeof(*hdr)) != checksum) {
stroese0621f6f2004-12-16 18:43:13 +0000152 printf ("Image %s bad header checksum\n", au_image[i].name);
153 return -1;
154 }
155 hdr->ih_hcrc = htonl(checksum);
156
157 /* check the type - could do this all in one gigantic if() */
158 if ((au_image[i].type == AU_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
159 printf ("Image %s wrong type\n", au_image[i].name);
160 return -1;
161 }
162 if ((au_image[i].type == AU_SCRIPT) && (hdr->ih_type != IH_TYPE_SCRIPT)) {
163 printf ("Image %s wrong type\n", au_image[i].name);
164 return -1;
165 }
166
167 /* recycle checksum */
168 checksum = ntohl(hdr->ih_size);
169
170#if 0 /* test-only */
171 /* for kernel and app the image header must also fit into flash */
172 if (idx != IDX_DISK)
173 checksum += sizeof(*hdr);
174 /* check the size does not exceed space in flash. HUSH scripts */
175 /* all have ausize[] set to 0 */
176 if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
177 printf ("Image %s is bigger than FLASH\n", au_image[i].name);
178 return -1;
179 }
180#endif
181
182 return 0;
183}
184
185
186int au_do_update(int i, long sz)
187{
188 image_header_t *hdr;
189 char *addr;
190 long start, end;
191 int off, rc;
192 uint nbytes;
193 int k;
194#if (CONFIG_COMMANDS & CFG_CMD_NAND)
195 int total;
196#endif
197
198 hdr = (image_header_t *)LOAD_ADDR;
199
200 switch (au_image[i].type) {
201 case AU_SCRIPT:
202 printf("Executing script %s\n", au_image[i].name);
203
204 /* execute a script */
205 if (hdr->ih_type == IH_TYPE_SCRIPT) {
206 addr = (char *)((char *)hdr + sizeof(*hdr));
207 /* stick a NULL at the end of the script, otherwise */
208 /* parse_string_outer() runs off the end. */
209 addr[ntohl(hdr->ih_size)] = 0;
210 addr += 8;
211
212 /*
213 * Replace cr/lf with ;
214 */
215 k = 0;
216 while (addr[k] != 0) {
217 if ((addr[k] == 10) || (addr[k] == 13)) {
218 addr[k] = ';';
219 }
220 k++;
221 }
222
223 run_command(addr, 0);
224 return 0;
225 }
226
227 break;
228
229 case AU_FIRMWARE:
230 case AU_NOR:
231 case AU_NAND:
232 start = au_image[i].start;
233 end = au_image[i].start + au_image[i].size - 1;
234
stroeseacdcd102005-03-16 20:58:31 +0000235 /*
236 * do not update firmware when image is already in flash.
237 */
238 if (au_image[i].type == AU_FIRMWARE) {
239 char *orig = (char*)start;
240 char *new = (char *)((char *)hdr + sizeof(*hdr));
241 nbytes = ntohl(hdr->ih_size);
242
243 while(--nbytes) {
244 if (*orig++ != *new++) {
245 break;
246 }
247 }
248 if (!nbytes) {
249 printf("Skipping firmware update - images are identical\n");
250 break;
251 }
252 }
253
stroese0621f6f2004-12-16 18:43:13 +0000254 /* unprotect the address range */
255 /* this assumes that ONLY the firmware is protected! */
256 if (au_image[i].type == AU_FIRMWARE) {
257 flash_sect_protect(0, start, end);
258 }
259
260 /*
261 * erase the address range.
262 */
263 if (au_image[i].type != AU_NAND) {
264 printf("Updating NOR FLASH with image %s\n", au_image[i].name);
265 debug ("flash_sect_erase(%lx, %lx);\n", start, end);
266 flash_sect_erase(start, end);
267 } else {
268#if (CONFIG_COMMANDS & CFG_CMD_NAND)
269 printf("Updating NAND FLASH with image %s\n", au_image[i].name);
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100270 debug ("nand_legacy_erase(%lx, %lx);\n", start, end);
271 rc = nand_legacy_erase (nand_dev_desc, start, end - start + 1, 0);
272 debug ("nand_legacy_erase returned %x\n", rc);
stroese0621f6f2004-12-16 18:43:13 +0000273#endif
274 }
275
276 udelay(10000);
277
278 /* strip the header - except for the kernel and ramdisk */
279 if (au_image[i].type != AU_FIRMWARE) {
280 addr = (char *)hdr;
281 off = sizeof(*hdr);
282 nbytes = sizeof(*hdr) + ntohl(hdr->ih_size);
283 } else {
284 addr = (char *)((char *)hdr + sizeof(*hdr));
285 off = 0;
286 nbytes = ntohl(hdr->ih_size);
287 }
288
289 /*
290 * copy the data from RAM to FLASH
291 */
292 if (au_image[i].type != AU_NAND) {
293 debug ("flash_write(%p, %lx %x)\n", addr, start, nbytes);
Stefan Roese18c5e642006-01-18 20:06:44 +0100294 rc = flash_write((char *)addr, start, nbytes);
stroese0621f6f2004-12-16 18:43:13 +0000295 } else {
296#if (CONFIG_COMMANDS & CFG_CMD_NAND)
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100297 debug ("nand_legacy_rw(%p, %lx %x)\n", addr, start, nbytes);
298 rc = nand_legacy_rw(nand_dev_desc, NANDRW_WRITE | NANDRW_JFFS2,
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200299 start, nbytes, (size_t *)&total, (uchar *)addr);
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100300 debug ("nand_legacy_rw: ret=%x total=%d nbytes=%d\n", rc, total, nbytes);
stroese0621f6f2004-12-16 18:43:13 +0000301#endif
302 }
303 if (rc != 0) {
304 printf("Flashing failed due to error %d\n", rc);
305 return -1;
306 }
307
308 /*
309 * check the dcrc of the copy
310 */
311 if (au_image[i].type != AU_NAND) {
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200312 rc = crc32 (0, (uchar *)(start + off), ntohl(hdr->ih_size));
stroese0621f6f2004-12-16 18:43:13 +0000313 } else {
314#if (CONFIG_COMMANDS & CFG_CMD_NAND)
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100315 rc = nand_legacy_rw(nand_dev_desc, NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP,
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200316 start, nbytes, (size_t *)&total, (uchar *)addr);
317 rc = crc32 (0, (uchar *)(addr + off), ntohl(hdr->ih_size));
stroese0621f6f2004-12-16 18:43:13 +0000318#endif
319 }
320 if (rc != ntohl(hdr->ih_dcrc)) {
321 printf ("Image %s Bad Data Checksum After COPY\n", au_image[i].name);
322 return -1;
323 }
324
325 /* protect the address range */
326 /* this assumes that ONLY the firmware is protected! */
327 if (au_image[i].type == AU_FIRMWARE) {
328 flash_sect_protect(1, start, end);
329 }
330
331 break;
332
333 default:
334 printf("Wrong image type selected!\n");
335 }
336
337 return 0;
338}
339
340
341static void process_macros (const char *input, char *output)
342{
343 char c, prev;
344 const char *varname_start = NULL;
345 int inputcnt = strlen (input);
346 int outputcnt = CFG_CBSIZE;
347 int state = 0; /* 0 = waiting for '$' */
348 /* 1 = waiting for '(' or '{' */
349 /* 2 = waiting for ')' or '}' */
350 /* 3 = waiting for ''' */
351#ifdef DEBUG_PARSER
352 char *output_start = output;
353
354 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
355#endif
356
357 prev = '\0'; /* previous character */
358
359 while (inputcnt && outputcnt) {
360 c = *input++;
361 inputcnt--;
362
363 if (state!=3) {
364 /* remove one level of escape characters */
365 if ((c == '\\') && (prev != '\\')) {
366 if (inputcnt-- == 0)
367 break;
368 prev = c;
369 c = *input++;
370 }
371 }
372
373 switch (state) {
374 case 0: /* Waiting for (unescaped) $ */
375 if ((c == '\'') && (prev != '\\')) {
376 state = 3;
377 break;
378 }
379 if ((c == '$') && (prev != '\\')) {
380 state++;
381 } else {
382 *(output++) = c;
383 outputcnt--;
384 }
385 break;
386 case 1: /* Waiting for ( */
387 if (c == '(' || c == '{') {
388 state++;
389 varname_start = input;
390 } else {
391 state = 0;
392 *(output++) = '$';
393 outputcnt--;
394
395 if (outputcnt) {
396 *(output++) = c;
397 outputcnt--;
398 }
399 }
400 break;
401 case 2: /* Waiting for ) */
402 if (c == ')' || c == '}') {
403 int i;
404 char envname[CFG_CBSIZE], *envval;
405 int envcnt = input-varname_start-1; /* Varname # of chars */
406
407 /* Get the varname */
408 for (i = 0; i < envcnt; i++) {
409 envname[i] = varname_start[i];
410 }
411 envname[i] = 0;
412
413 /* Get its value */
414 envval = getenv (envname);
415
416 /* Copy into the line if it exists */
417 if (envval != NULL)
418 while ((*envval) && outputcnt) {
419 *(output++) = *(envval++);
420 outputcnt--;
421 }
422 /* Look for another '$' */
423 state = 0;
424 }
425 break;
426 case 3: /* Waiting for ' */
427 if ((c == '\'') && (prev != '\\')) {
428 state = 0;
429 } else {
430 *(output++) = c;
431 outputcnt--;
432 }
433 break;
434 }
435 prev = c;
436 }
437
438 if (outputcnt)
439 *output = 0;
440
441#ifdef DEBUG_PARSER
442 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
443 strlen(output_start), output_start);
444#endif
445}
446
447
448/*
449 * this is called from board_init() after the hardware has been set up
450 * and is usable. That seems like a good time to do this.
451 * Right now the return value is ignored.
452 */
453int do_auto_update(void)
454{
455 block_dev_desc_t *stor_dev;
456 long sz;
457 int i, res, cnt, old_ctrlc, got_ctrlc;
458 char buffer[32];
459 char str[80];
460
461 /*
462 * Check whether a CompactFlash is inserted
463 */
464 if (ide_dev_desc[0].type == DEV_TYPE_UNKNOWN) {
465 return -1; /* no disk detected! */
466 }
467
468 /* check whether it has a partition table */
469 stor_dev = get_dev("ide", 0);
470 if (stor_dev == NULL) {
471 debug ("Uknown device type\n");
472 return -1;
473 }
474 if (fat_register_device(stor_dev, 1) != 0) {
475 debug ("Unable to register ide disk 0:1 for fatls\n");
476 return -1;
477 }
478
479 /*
480 * Check if magic file is present
481 */
482 if (do_fat_read(AU_MAGIC_FILE, buffer, sizeof(buffer), LS_NO) <= 0) {
483 return -1;
484 }
485
486#ifdef CONFIG_AUTO_UPDATE_SHOW
487 board_auto_update_show(1);
488#endif
489 puts("\nAutoUpdate Disk detected! Trying to update system...\n");
490
491 /* make sure that we see CTRL-C and save the old state */
492 old_ctrlc = disable_ctrlc(0);
493
494 /* just loop thru all the possible files */
495 for (i = 0; i < N_AU_IMAGES; i++) {
496 /*
497 * Try to expand the environment var in the fname
498 */
499 process_macros(au_image[i].name, str);
500 strcpy(au_image[i].name, str);
501
502 printf("Reading %s ...", au_image[i].name);
503 /* just read the header */
504 sz = do_fat_read(au_image[i].name, LOAD_ADDR, sizeof(image_header_t), LS_NO);
505 debug ("read %s sz %ld hdr %d\n",
506 au_image[i].name, sz, sizeof(image_header_t));
507 if (sz <= 0 || sz < sizeof(image_header_t)) {
508 puts(" not found\n");
509 continue;
510 }
511 if (au_check_header_valid(i, sz) < 0) {
512 puts(" header not valid\n");
513 continue;
514 }
515 sz = do_fat_read(au_image[i].name, LOAD_ADDR, MAX_LOADSZ, LS_NO);
516 debug ("read %s sz %ld hdr %d\n",
517 au_image[i].name, sz, sizeof(image_header_t));
518 if (sz <= 0 || sz <= sizeof(image_header_t)) {
519 puts(" not found\n");
520 continue;
521 }
522 if (au_check_cksum_valid(i, sz) < 0) {
523 puts(" checksum not valid\n");
524 continue;
525 }
526 puts(" done\n");
527
528 do {
529 res = au_do_update(i, sz);
530 /* let the user break out of the loop */
531 if (ctrlc() || had_ctrlc()) {
532 clear_ctrlc();
533 if (res < 0)
534 got_ctrlc = 1;
535 break;
536 }
537 cnt++;
538 } while (res < 0);
539 }
540
541 /* restore the old state */
542 disable_ctrlc(old_ctrlc);
543
544 puts("AutoUpdate finished\n\n");
545#ifdef CONFIG_AUTO_UPDATE_SHOW
546 board_auto_update_show(0);
547#endif
548
549 return 0;
550}
551
552
553int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
554{
555 do_auto_update();
556
557 return 0;
558}
559U_BOOT_CMD(
560 autoupd, 1, 1, auto_update,
561 "autoupd - Automatically update images\n",
562 NULL
563);
564#endif /* CONFIG_AUTO_UPDATE */