]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootm.c
* Patch by Daniel Engström, 13 Nov 2002:
[karo-tx-uboot.git] / common / cmd_bootm.c
1 /*
2  * (C) Copyright 2000-2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * Boot support
26  */
27 #include <common.h>
28 #include <watchdog.h>
29 #include <command.h>
30 #include <cmd_boot.h>
31 #include <image.h>
32 #include <malloc.h>
33 #include <zlib.h>
34 #include <asm/byteorder.h>
35 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
36 #include <rtc.h>
37 #endif
38
39 #ifdef CFG_HUSH_PARSER
40 #include <hush.h>
41 #endif
42
43 #ifdef CONFIG_SHOW_BOOT_PROGRESS
44 # include <status_led.h>
45 # define SHOW_BOOT_PROGRESS(arg)        show_boot_progress(arg)
46 #else
47 # define SHOW_BOOT_PROGRESS(arg)
48 #endif
49
50 #ifdef CFG_INIT_RAM_LOCK
51 #include <asm/cache.h>
52 #endif
53
54 /*
55  * Some systems (for example LWMON) have very short watchdog periods;
56  * we must make sure to split long operations like memmove() or
57  * crc32() into reasonable chunks.
58  */
59 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
60 # define CHUNKSZ (64 * 1024)
61 #endif
62
63 int  gunzip (void *, int, unsigned char *, int *);
64
65 static void *zalloc(void *, unsigned, unsigned);
66 static void zfree(void *, void *, unsigned);
67
68 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
69 static int image_info (unsigned long addr);
70 #endif
71 static void print_type (image_header_t *hdr);
72
73 #ifdef __I386__
74 image_header_t *fake_header(image_header_t *hdr, void *ptr, int size);
75 #endif
76
77 /*
78  *  Continue booting an OS image; caller already has:
79  *  - copied image header to global variable `header'
80  *  - checked header magic number, checksums (both header & image),
81  *  - verified image architecture (PPC) and type (KERNEL or MULTI),
82  *  - loaded (first part of) image to header load address,
83  *  - disabled interrupts.
84  */
85 typedef void boot_os_Fcn (cmd_tbl_t *cmdtp, int flag,
86                           int   argc, char *argv[],
87                           ulong addr,           /* of image to boot */
88                           ulong *len_ptr,       /* multi-file image length table */
89                           int   verify);        /* getenv("verify")[0] != 'n' */
90
91 #ifdef CONFIG_PPC
92 static boot_os_Fcn do_bootm_linux;
93 #else
94 extern boot_os_Fcn do_bootm_linux;
95 #endif
96 static boot_os_Fcn do_bootm_netbsd;
97 #if (CONFIG_COMMANDS & CFG_CMD_ELF)
98 static boot_os_Fcn do_bootm_vxworks;
99 static boot_os_Fcn do_bootm_qnxelf;
100 int do_bootvx ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] );
101 int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] );
102 #endif /* CFG_CMD_ELF */
103
104 image_header_t header;
105
106 ulong load_addr = CFG_LOAD_ADDR;                /* Default Load Address */
107
108 int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
109 {
110         ulong   iflag;
111         ulong   addr;
112         ulong   data, len, checksum;
113         ulong  *len_ptr;
114         int     i, verify;
115         char    *name, *s;
116         int     (*appl)(cmd_tbl_t *, int, int, char *[]);
117         image_header_t *hdr = &header;
118
119         s = getenv ("verify");
120         verify = (s && (*s == 'n')) ? 0 : 1;
121
122         if (argc < 2) {
123                 addr = load_addr;
124         } else {
125                 addr = simple_strtoul(argv[1], NULL, 16);
126         }
127
128         SHOW_BOOT_PROGRESS (1);
129         printf ("## Booting image at %08lx ...\n", addr);
130
131         /* Copy header so we can blank CRC field for re-calculation */
132         memmove (&header, (char *)addr, sizeof(image_header_t));
133
134         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
135 #ifdef __I386__ /* correct image format not implemented yet - fake it */
136                 if (fake_header(hdr, (void*)addr, -1) != NULL) {
137                         /* to compensate for the addition below */
138                         addr -= sizeof(image_header_t);
139                         /* turnof verify,
140                          * fake_header() does not fake the data crc
141                          */
142                         verify = 0;
143                 } else
144 #endif  /* __I386__ */
145             {
146                 printf ("Bad Magic Number\n");
147                 SHOW_BOOT_PROGRESS (-1);
148                 return 1;
149             }
150         }
151         SHOW_BOOT_PROGRESS (2);
152
153         data = (ulong)&header;
154         len  = sizeof(image_header_t);
155
156         checksum = ntohl(hdr->ih_hcrc);
157         hdr->ih_hcrc = 0;
158
159         if (crc32 (0, (char *)data, len) != checksum) {
160                 printf ("Bad Header Checksum\n");
161                 SHOW_BOOT_PROGRESS (-2);
162                 return 1;
163         }
164         SHOW_BOOT_PROGRESS (3);
165
166         /* for multi-file images we need the data part, too */
167         print_image_hdr (hdr);
168
169         data = addr + sizeof(image_header_t);
170         len  = ntohl(hdr->ih_size);
171
172         if (verify) {
173                 printf ("   Verifying Checksum ... ");
174                 if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) {
175                         printf ("Bad Data CRC\n");
176                         SHOW_BOOT_PROGRESS (-3);
177                         return 1;
178                 }
179                 printf ("OK\n");
180         }
181         SHOW_BOOT_PROGRESS (4);
182
183         len_ptr = (ulong *)data;
184
185 #if defined(__PPC__)
186         if (hdr->ih_arch != IH_CPU_PPC)
187 #elif defined(__ARM__)
188         if (hdr->ih_arch != IH_CPU_ARM)
189 #elif defined(__I386__)
190         if (hdr->ih_arch != IH_CPU_I386)
191 #else
192 # error Unknown CPU type
193 #endif
194         {
195                 printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch);
196                 SHOW_BOOT_PROGRESS (-4);
197                 return 1;
198         }
199         SHOW_BOOT_PROGRESS (5);
200
201         switch (hdr->ih_type) {
202         case IH_TYPE_STANDALONE:        name = "Standalone Application";
203                                         break;
204         case IH_TYPE_KERNEL:            name = "Kernel Image";
205                                         break;
206         case IH_TYPE_MULTI:             name = "Multi-File Image";
207                                         len  = ntohl(len_ptr[0]);
208                                         /* OS kernel is always the first image */
209                                         data += 8; /* kernel_len + terminator */
210                                         for (i=1; len_ptr[i]; ++i)
211                                                 data += 4;
212                                         break;
213         default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
214                 SHOW_BOOT_PROGRESS (-5);
215                 return 1;
216         }
217         SHOW_BOOT_PROGRESS (6);
218
219         /*
220          * We have reached the point of no return: we are going to
221          * overwrite all exception vector code, so we cannot easily
222          * recover from any failures any more...
223          */
224
225         iflag = disable_interrupts();
226
227         switch (hdr->ih_comp) {
228         case IH_COMP_NONE:
229                 if(ntohl(hdr->ih_load) == addr) {
230                         printf ("   XIP %s ... ", name);
231                 } else {
232 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
233                         size_t l = len;
234                         void *to = (void *)ntohl(hdr->ih_load);
235                         void *from = (void *)data;
236
237                         printf ("   Loading %s ... ", name);
238
239                         while (l > 0) {
240                                 size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
241                                 WATCHDOG_RESET();
242                                 memmove (to, from, tail);
243                                 to += tail;
244                                 from += tail;
245                                 l -= tail;
246                         }
247 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
248                         memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
249 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
250                 }
251                 break;
252         case IH_COMP_GZIP:
253                 printf ("   Uncompressing %s ... ", name);
254                 if (gunzip ((void *)ntohl(hdr->ih_load), 0x400000,
255                             (uchar *)data, (int *)&len) != 0) {
256                         printf ("GUNZIP ERROR - must RESET board to recover\n");
257                         SHOW_BOOT_PROGRESS (-6);
258                         do_reset (cmdtp, flag, argc, argv);
259                 }
260                 break;
261         default:
262                 if (iflag)
263                         enable_interrupts();
264                 printf ("Unimplemented compression type %d\n", hdr->ih_comp);
265                 SHOW_BOOT_PROGRESS (-7);
266                 return 1;
267         }
268         printf ("OK\n");
269         SHOW_BOOT_PROGRESS (7);
270
271         switch (hdr->ih_type) {
272         case IH_TYPE_STANDALONE:
273                 appl = (int (*)(cmd_tbl_t *, int, int, char *[]))ntohl(hdr->ih_ep);
274                 if (iflag)
275                         enable_interrupts();
276
277                 (*appl)(cmdtp, flag, argc-1, &argv[1]);
278                 break;
279         case IH_TYPE_KERNEL:
280         case IH_TYPE_MULTI:
281                 /* handled below */
282                 break;
283         default:
284                 if (iflag)
285                         enable_interrupts();
286                 printf ("Can't boot image type %d\n", hdr->ih_type);
287                 SHOW_BOOT_PROGRESS (-8);
288                 return 1;
289         }
290         SHOW_BOOT_PROGRESS (8);
291
292         switch (hdr->ih_os) {
293         default:                        /* handled by (original) Linux case */
294         case IH_OS_LINUX:
295             do_bootm_linux  (cmdtp, flag, argc, argv,
296                              addr, len_ptr, verify);
297             break;
298         case IH_OS_NETBSD:
299             do_bootm_netbsd (cmdtp, flag, argc, argv,
300                              addr, len_ptr, verify);
301             break;
302 #if (CONFIG_COMMANDS & CFG_CMD_ELF)
303         case IH_OS_VXWORKS:
304             do_bootm_vxworks (cmdtp, flag, argc, argv,
305                               addr, len_ptr, verify);
306             break;
307         case IH_OS_QNX:
308             do_bootm_qnxelf (cmdtp, flag, argc, argv,
309                               addr, len_ptr, verify);
310             break;
311 #endif /* CFG_CMD_ELF */
312         }
313
314         SHOW_BOOT_PROGRESS (-9);
315 #ifdef DEBUG
316         printf ("\n## Control returned to monitor - resetting...\n");
317         do_reset (cmdtp, flag, argc, argv);
318 #endif
319         return 1;
320 }
321
322 #ifdef CONFIG_PPC
323 static void
324 do_bootm_linux (cmd_tbl_t *cmdtp, int flag,
325                 int     argc, char *argv[],
326                 ulong   addr,
327                 ulong   *len_ptr,
328                 int     verify)
329 {
330         DECLARE_GLOBAL_DATA_PTR;
331
332         ulong   sp;
333         ulong   len, checksum;
334         ulong   initrd_start, initrd_end;
335         ulong   cmd_start, cmd_end;
336         ulong   initrd_high;
337         ulong   data;
338         char    *cmdline;
339         char    *s;
340         bd_t    *kbd;
341         void    (*kernel)(bd_t *, ulong, ulong, ulong, ulong);
342         image_header_t *hdr = &header;
343
344         if ((s = getenv ("initrd_high")) != NULL) {
345                 /* a value of "no" or a similar string will act like 0,
346                  * turning the "load high" feature off. This is intentional.
347                  */
348                 initrd_high = simple_strtoul(s, NULL, 16);
349         } else {                        /* not set, no restrictions to load high */
350                 initrd_high = ~0;
351         }
352
353 #ifdef CONFIG_LOGBUFFER
354         kbd=gd->bd;
355         if ((s = getenv ("logstart")) != NULL) {
356                 kbd->bi_sramstart = simple_strtoul(s, NULL, 16);
357                 /* Prevent initrd from overwriting logbuffer */
358                 if (initrd_high < kbd->bi_sramstart)
359                         initrd_high = kbd->bi_sramstart-1024;
360         }
361         debug ("## Logbuffer at 0x%08lX ", kbd->bi_sramstart);
362 #endif
363
364         /*
365          * Booting a (Linux) kernel image
366          *
367          * Allocate space for command line and board info - the
368          * address should be as high as possible within the reach of
369          * the kernel (see CFG_BOOTMAPSZ settings), but in unused
370          * memory, which means far enough below the current stack
371          * pointer.
372          */
373
374         asm( "mr %0,1": "=r"(sp) : );
375
376         debug ("## Current stack ends at 0x%08lX ", sp);
377
378         sp -= 2048;             /* just to be sure */
379         if (sp > CFG_BOOTMAPSZ)
380                 sp = CFG_BOOTMAPSZ;
381         sp &= ~0xF;
382
383         debug ("=> set upper limit to 0x%08lX\n", sp);
384
385         cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
386         kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF);
387
388         if ((s = getenv("bootargs")) == NULL)
389                 s = "";
390
391         strcpy (cmdline, s);
392
393         cmd_start    = (ulong)&cmdline[0];
394         cmd_end      = cmd_start + strlen(cmdline);
395
396         *kbd = *(gd->bd);
397
398 #ifdef  DEBUG
399         printf ("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end);
400
401         do_bdinfo (NULL, 0, 0, NULL);
402 #endif
403
404         if ((s = getenv ("clocks_in_mhz")) != NULL) {
405                 /* convert all clock information to MHz */
406                 kbd->bi_intfreq /= 1000000L;
407                 kbd->bi_busfreq /= 1000000L;
408 #if defined(CONFIG_8260)
409                 kbd->bi_cpmfreq /= 1000000L;
410                 kbd->bi_brgfreq /= 1000000L;
411                 kbd->bi_sccfreq /= 1000000L;
412                 kbd->bi_vco     /= 1000000L;
413 #endif /* CONFIG_8260 */
414         }
415
416         kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep;
417
418         /*
419          * Check if there is an initrd image
420          */
421         if (argc >= 3) {
422                 SHOW_BOOT_PROGRESS (9);
423
424                 addr = simple_strtoul(argv[2], NULL, 16);
425
426                 printf ("## Loading RAMDisk Image at %08lx ...\n", addr);
427
428                 /* Copy header so we can blank CRC field for re-calculation */
429                 memmove (&header, (char *)addr, sizeof(image_header_t));
430
431                 if (hdr->ih_magic  != IH_MAGIC) {
432                         printf ("Bad Magic Number\n");
433                         SHOW_BOOT_PROGRESS (-10);
434                         do_reset (cmdtp, flag, argc, argv);
435                 }
436
437                 data = (ulong)&header;
438                 len  = sizeof(image_header_t);
439
440                 checksum = hdr->ih_hcrc;
441                 hdr->ih_hcrc = 0;
442
443                 if (crc32 (0, (char *)data, len) != checksum) {
444                         printf ("Bad Header Checksum\n");
445                         SHOW_BOOT_PROGRESS (-11);
446                         do_reset (cmdtp, flag, argc, argv);
447                 }
448
449                 SHOW_BOOT_PROGRESS (10);
450
451                 print_image_hdr (hdr);
452
453                 data = addr + sizeof(image_header_t);
454                 len  = hdr->ih_size;
455
456                 if (verify) {
457                         ulong csum = 0;
458 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
459                         ulong cdata = data, edata = cdata + len;
460 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
461
462                         printf ("   Verifying Checksum ... ");
463
464 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
465
466                         while (cdata < edata) {
467                                 ulong chunk = edata - cdata;
468
469                                 if (chunk > CHUNKSZ)
470                                         chunk = CHUNKSZ;
471                                 csum = crc32 (csum, (char *)cdata, chunk);
472                                 cdata += chunk;
473
474                                 WATCHDOG_RESET();
475                         }
476 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
477                         csum = crc32 (0, (char *)data, len);
478 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
479
480                         if (csum != hdr->ih_dcrc) {
481                                 printf ("Bad Data CRC\n");
482                                 SHOW_BOOT_PROGRESS (-12);
483                                 do_reset (cmdtp, flag, argc, argv);
484                         }
485                         printf ("OK\n");
486                 }
487
488                 SHOW_BOOT_PROGRESS (11);
489
490                 if ((hdr->ih_os   != IH_OS_LINUX)       ||
491                     (hdr->ih_arch != IH_CPU_PPC)        ||
492                     (hdr->ih_type != IH_TYPE_RAMDISK)   ) {
493                         printf ("No Linux PPC Ramdisk Image\n");
494                         SHOW_BOOT_PROGRESS (-13);
495                         do_reset (cmdtp, flag, argc, argv);
496                 }
497
498                 /*
499                  * Now check if we have a multifile image
500                  */
501         } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
502                 u_long tail    = ntohl(len_ptr[0]) % 4;
503                 int i;
504
505                 SHOW_BOOT_PROGRESS (13);
506
507                 /* skip kernel length and terminator */
508                 data = (ulong)(&len_ptr[2]);
509                 /* skip any additional image length fields */
510                 for (i=1; len_ptr[i]; ++i)
511                         data += 4;
512                 /* add kernel length, and align */
513                 data += ntohl(len_ptr[0]);
514                 if (tail) {
515                         data += 4 - tail;
516                 }
517
518                 len   = ntohl(len_ptr[1]);
519
520         } else {
521                 /*
522                  * no initrd image
523                  */
524                 SHOW_BOOT_PROGRESS (14);
525
526                 len = data = 0;
527         }
528
529         if (!data) {
530                 debug ("No initrd\n");
531         }
532
533         if (data) {
534                 initrd_start  = (ulong)kbd - len;
535                 initrd_start &= ~(4096 - 1);    /* align on page */
536
537                 if (initrd_high) {
538                         ulong nsp;
539
540                         /*
541                          * the inital ramdisk does not need to be within
542                          * CFG_BOOTMAPSZ as it is not accessed until after
543                          * the mm system is initialised.
544                          *
545                          * do the stack bottom calculation again and see if
546                          * the initrd will fit just below the monitor stack
547                          * bottom without overwriting the area allocated
548                          * above for command line args and board info.
549                          */
550                         asm( "mr %0,1": "=r"(nsp) : );
551                         nsp -= 2048;            /* just to be sure */
552                         nsp &= ~0xF;
553                         if (nsp > initrd_high)  /* limit as specified */
554                                 nsp = initrd_high;
555                         nsp -= len;
556                         nsp &= ~(4096 - 1);     /* align on page */
557                         if (nsp >= sp)
558                                 initrd_start = nsp;
559                 }
560
561                 SHOW_BOOT_PROGRESS (12);
562
563                 debug ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n",
564                         data, data + len - 1, len, len);
565
566                 initrd_end    = initrd_start + len;
567                 printf ("   Loading Ramdisk to %08lx, end %08lx ... ",
568                         initrd_start, initrd_end);
569 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
570                 {
571                         size_t l = len;
572                         void *to = (void *)initrd_start;
573                         void *from = (void *)data;
574
575                         while (l > 0) {
576                                 size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
577                                 WATCHDOG_RESET();
578                                 memmove (to, from, tail);
579                                 to += tail;
580                                 from += tail;
581                                 l -= tail;
582                         }
583                 }
584 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
585                 memmove ((void *)initrd_start, (void *)data, len);
586 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
587                 printf ("OK\n");
588         } else {
589                 initrd_start = 0;
590                 initrd_end = 0;
591         }
592
593
594         debug ("## Transferring control to Linux (at address %08lx) ...\n",
595                 (ulong)kernel);
596
597         SHOW_BOOT_PROGRESS (15);
598
599 #ifdef CFG_INIT_RAM_LOCK
600         unlock_ram_in_cache();
601 #endif
602         /*
603          * Linux Kernel Parameters:
604          *   r3: ptr to board info data
605          *   r4: initrd_start or 0 if no initrd
606          *   r5: initrd_end - unused if r4 is 0
607          *   r6: Start of command line string
608          *   r7: End   of command line string
609          */
610         (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
611 }
612 #endif /* CONFIG_ARM */
613
614 static void
615 do_bootm_netbsd (cmd_tbl_t *cmdtp, int flag,
616                 int     argc, char *argv[],
617                 ulong   addr,
618                 ulong   *len_ptr,
619                 int     verify)
620 {
621         DECLARE_GLOBAL_DATA_PTR;
622
623         image_header_t *hdr = &header;
624
625         void    (*loader)(bd_t *, image_header_t *, char *, char *);
626         image_header_t *img_addr;
627         char     *consdev;
628         char     *cmdline;
629
630
631         /*
632          * Booting a (NetBSD) kernel image
633          *
634          * This process is pretty similar to a standalone application:
635          * The (first part of an multi-) image must be a stage-2 loader,
636          * which in turn is responsible for loading & invoking the actual
637          * kernel.  The only differences are the parameters being passed:
638          * besides the board info strucure, the loader expects a command
639          * line, the name of the console device, and (optionally) the
640          * address of the original image header.
641          */
642
643         img_addr = 0;
644         if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1]))
645                 img_addr = (image_header_t *) addr;
646
647
648         consdev = "";
649 #if   defined (CONFIG_8xx_CONS_SMC1)
650         consdev = "smc1";
651 #elif defined (CONFIG_8xx_CONS_SMC2)
652         consdev = "smc2";
653 #elif defined (CONFIG_8xx_CONS_SCC2)
654         consdev = "scc2";
655 #elif defined (CONFIG_8xx_CONS_SCC3)
656         consdev = "scc3";
657 #endif
658
659         if (argc > 2) {
660                 ulong len;
661                 int   i;
662
663                 for (i=2, len=0 ; i<argc ; i+=1)
664                         len += strlen (argv[i]) + 1;
665                 cmdline = malloc (len);
666
667                 for (i=2, len=0 ; i<argc ; i+=1) {
668                         if (i > 2)
669                                 cmdline[len++] = ' ';
670                         strcpy (&cmdline[len], argv[i]);
671                         len += strlen (argv[i]);
672                 }
673         } else if ((cmdline = getenv("bootargs")) == NULL) {
674                 cmdline = "";
675         }
676
677         loader = (void (*)(bd_t *, image_header_t *, char *, char *)) hdr->ih_ep;
678
679         printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
680                 (ulong)loader);
681
682         SHOW_BOOT_PROGRESS (15);
683
684         /*
685          * NetBSD Stage-2 Loader Parameters:
686          *   r3: ptr to board info data
687          *   r4: image address
688          *   r5: console device
689          *   r6: boot args string
690          */
691         (*loader) (gd->bd, img_addr, consdev, cmdline);
692 }
693
694 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
695 int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
696 {
697         int rcode = 0;
698 #ifndef CFG_HUSH_PARSER
699         if (run_command (getenv ("bootcmd"), flag) < 0) rcode = 1;
700 #else
701         if (parse_string_outer(getenv("bootcmd"),
702                 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0 ) rcode = 1;
703 #endif
704         return rcode;
705 }
706 #endif
707
708 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
709 int do_iminfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
710 {
711         int     arg;
712         ulong   addr;
713         int     rcode=0;
714
715         if (argc < 2) {
716                 return image_info (load_addr);
717         }
718
719         for (arg=1; arg <argc; ++arg) {
720                 addr = simple_strtoul(argv[arg], NULL, 16);
721                 if (image_info (addr) != 0) rcode = 1;
722         }
723         return rcode;
724 }
725
726 static int image_info (ulong addr)
727 {
728         ulong   data, len, checksum;
729         image_header_t *hdr = &header;
730
731         printf ("\n## Checking Image at %08lx ...\n", addr);
732
733         /* Copy header so we can blank CRC field for re-calculation */
734         memmove (&header, (char *)addr, sizeof(image_header_t));
735
736         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
737                 printf ("   Bad Magic Number\n");
738                 return 1;
739         }
740
741         data = (ulong)&header;
742         len  = sizeof(image_header_t);
743
744         checksum = ntohl(hdr->ih_hcrc);
745         hdr->ih_hcrc = 0;
746
747         if (crc32 (0, (char *)data, len) != checksum) {
748                 printf ("   Bad Header Checksum\n");
749                 return 1;
750         }
751
752         /* for multi-file images we need the data part, too */
753         print_image_hdr ((image_header_t *)addr);
754
755         data = addr + sizeof(image_header_t);
756         len  = ntohl(hdr->ih_size);
757
758         printf ("   Verifying Checksum ... ");
759         if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) {
760                 printf ("   Bad Data CRC\n");
761                 return 1;
762         }
763         printf ("OK\n");
764         return 0;
765 }
766 #endif  /* CFG_CMD_IMI */
767
768 void
769 print_image_hdr (image_header_t *hdr)
770 {
771 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
772         time_t timestamp = (time_t)ntohl(hdr->ih_time);
773         struct rtc_time tm;
774 #endif
775
776         printf ("   Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name);
777 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
778         to_tm (timestamp, &tm);
779         printf ("   Created:      %4d-%02d-%02d  %2d:%02d:%02d UTC\n",
780                 tm.tm_year, tm.tm_mon, tm.tm_mday,
781                 tm.tm_hour, tm.tm_min, tm.tm_sec);
782 #endif  /* CFG_CMD_DATE, CONFIG_TIMESTAMP */
783         printf ("   Image Type:   "); print_type(hdr); printf ("\n");
784         printf ("   Data Size:    %d Bytes = ", ntohl(hdr->ih_size));
785         print_size (ntohl(hdr->ih_size), "\n");
786         printf ("   Load Address: %08x\n", ntohl(hdr->ih_load));
787         printf ("   Entry Point:  %08x\n", ntohl(hdr->ih_ep));
788
789         if (hdr->ih_type == IH_TYPE_MULTI) {
790                 int i;
791                 ulong len;
792                 ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t));
793
794                 printf ("   Contents:\n");
795                 for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
796                         printf ("   Image %d: %8ld Bytes = ", i, len);
797                         print_size (len, "\n");
798                 }
799         }
800 }
801
802
803 static void
804 print_type (image_header_t *hdr)
805 {
806         char *os, *arch, *type, *comp;
807
808         switch (hdr->ih_os) {
809         case IH_OS_INVALID:     os = "Invalid OS";              break;
810         case IH_OS_NETBSD:      os = "NetBSD";                  break;
811         case IH_OS_LINUX:       os = "Linux";                   break;
812         case IH_OS_VXWORKS:     os = "VxWorks";                 break;
813         case IH_OS_QNX:         os = "QNX";                     break;
814         case IH_OS_U_BOOT:      os = "U-Boot";                  break;
815         default:                os = "Unknown OS";              break;
816         }
817
818         switch (hdr->ih_arch) {
819         case IH_CPU_INVALID:    arch = "Invalid CPU";           break;
820         case IH_CPU_ALPHA:      arch = "Alpha";                 break;
821         case IH_CPU_ARM:        arch = "ARM";                   break;
822         case IH_CPU_I386:       arch = "Intel x86";             break;
823         case IH_CPU_IA64:       arch = "IA64";                  break;
824         case IH_CPU_MIPS:       arch = "MIPS";                  break;
825         case IH_CPU_MIPS64:     arch = "MIPS 64 Bit";           break;
826         case IH_CPU_PPC:        arch = "PowerPC";               break;
827         case IH_CPU_S390:       arch = "IBM S390";              break;
828         case IH_CPU_SH:         arch = "SuperH";                break;
829         case IH_CPU_SPARC:      arch = "SPARC";                 break;
830         case IH_CPU_SPARC64:    arch = "SPARC 64 Bit";          break;
831         default:                arch = "Unknown Architecture";  break;
832         }
833
834         switch (hdr->ih_type) {
835         case IH_TYPE_INVALID:   type = "Invalid Image";         break;
836         case IH_TYPE_STANDALONE:type = "Standalone Program";    break;
837         case IH_TYPE_KERNEL:    type = "Kernel Image";          break;
838         case IH_TYPE_RAMDISK:   type = "RAMDisk Image";         break;
839         case IH_TYPE_MULTI:     type = "Multi-File Image";      break;
840         case IH_TYPE_FIRMWARE:  type = "Firmware";              break;
841         case IH_TYPE_SCRIPT:    type = "Script";                break;
842         default:                type = "Unknown Image";         break;
843         }
844
845         switch (hdr->ih_comp) {
846         case IH_COMP_NONE:      comp = "uncompressed";          break;
847         case IH_COMP_GZIP:      comp = "gzip compressed";       break;
848         case IH_COMP_BZIP2:     comp = "bzip2 compressed";      break;
849         default:                comp = "unknown compression";   break;
850         }
851
852         printf ("%s %s %s (%s)", arch, os, type, comp);
853 }
854
855 #define ZALLOC_ALIGNMENT        16
856
857 static void *zalloc(void *x, unsigned items, unsigned size)
858 {
859         void *p;
860
861         size *= items;
862         size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
863
864         p = malloc (size);
865
866         return (p);
867 }
868
869 static void zfree(void *x, void *addr, unsigned nb)
870 {
871         free (addr);
872 }
873
874 #define HEAD_CRC        2
875 #define EXTRA_FIELD     4
876 #define ORIG_NAME       8
877 #define COMMENT         0x10
878 #define RESERVED        0xe0
879
880 #define DEFLATED        8
881
882 int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
883 {
884         z_stream s;
885         int r, i, flags;
886
887         /* skip header */
888         i = 10;
889         flags = src[3];
890         if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
891                 printf ("Error: Bad gzipped data\n");
892                 return (-1);
893         }
894         if ((flags & EXTRA_FIELD) != 0)
895                 i = 12 + src[10] + (src[11] << 8);
896         if ((flags & ORIG_NAME) != 0)
897                 while (src[i++] != 0)
898                         ;
899         if ((flags & COMMENT) != 0)
900                 while (src[i++] != 0)
901                         ;
902         if ((flags & HEAD_CRC) != 0)
903                 i += 2;
904         if (i >= *lenp) {
905                 printf ("Error: gunzip out of data in header\n");
906                 return (-1);
907         }
908
909         s.zalloc = zalloc;
910         s.zfree = zfree;
911 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
912         s.outcb = (cb_func)WATCHDOG_RESET;
913 #else
914         s.outcb = Z_NULL;
915 #endif  /* CONFIG_HW_WATCHDOG */
916
917         r = inflateInit2(&s, -MAX_WBITS);
918         if (r != Z_OK) {
919                 printf ("Error: inflateInit2() returned %d\n", r);
920                 return (-1);
921         }
922         s.next_in = src + i;
923         s.avail_in = *lenp - i;
924         s.next_out = dst;
925         s.avail_out = dstlen;
926         r = inflate(&s, Z_FINISH);
927         if (r != Z_OK && r != Z_STREAM_END) {
928                 printf ("Error: inflate() returned %d\n", r);
929                 return (-1);
930         }
931         *lenp = s.next_out - (unsigned char *) dst;
932         inflateEnd(&s);
933
934         return (0);
935 }
936
937 #if (CONFIG_COMMANDS & CFG_CMD_ELF)
938 static void
939 do_bootm_vxworks (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
940                   ulong addr, ulong *len_ptr, int verify)
941 {
942         image_header_t *hdr = &header;
943         char str[80];
944
945         sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */
946         setenv("loadaddr", str);
947         do_bootvx(cmdtp, 0, 0, NULL);
948 }
949
950 static void
951 do_bootm_qnxelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
952                  ulong addr, ulong *len_ptr, int verify)
953 {
954         image_header_t *hdr = &header;
955         char *local_args[2];
956         char str[16];
957
958         sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */
959         local_args[0] = argv[0];
960         local_args[1] = str;    /* and provide it via the arguments */
961         do_bootelf(cmdtp, 0, 2, local_args);
962 }
963 #endif /* CFG_CMD_ELF */