]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootm.c
[new uImage] Rename and move print_image_hdr() routine
[karo-tx-uboot.git] / common / cmd_bootm.c
1 /*
2  * (C) Copyright 2000-2006
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 #define DEBUG
25
26 /*
27  * Boot support
28  */
29 #include <common.h>
30 #include <watchdog.h>
31 #include <command.h>
32 #include <image.h>
33 #include <malloc.h>
34 #include <zlib.h>
35 #include <bzlib.h>
36 #include <environment.h>
37 #include <asm/byteorder.h>
38
39 #ifdef CFG_HUSH_PARSER
40 #include <hush.h>
41 #endif
42
43 DECLARE_GLOBAL_DATA_PTR;
44
45 extern int gunzip (void *dst, int dstlen, unsigned char *src, unsigned long *lenp);
46 #ifndef CFG_BOOTM_LEN
47 #define CFG_BOOTM_LEN   0x800000        /* use 8MByte as default max gunzip size */
48 #endif
49
50 #ifdef CONFIG_BZIP2
51 extern void bz_internal_error(int);
52 #endif
53
54 #if defined(CONFIG_CMD_IMI)
55 static int image_info (unsigned long addr);
56 #endif
57
58 #if defined(CONFIG_CMD_IMLS)
59 #include <flash.h>
60 extern flash_info_t flash_info[]; /* info for FLASH chips */
61 static int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
62 #endif
63
64 #ifdef CONFIG_SILENT_CONSOLE
65 static void fixup_silent_linux (void);
66 #endif
67
68 static image_header_t *get_kernel (cmd_tbl_t *cmdtp, int flag,
69                 int argc, char *argv[], int verify,
70                 ulong *os_data, ulong *os_len);
71 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
72
73 /*
74  *  Continue booting an OS image; caller already has:
75  *  - copied image header to global variable `header'
76  *  - checked header magic number, checksums (both header & image),
77  *  - verified image architecture (PPC) and type (KERNEL or MULTI),
78  *  - loaded (first part of) image to header load address,
79  *  - disabled interrupts.
80  */
81 typedef void boot_os_fn (cmd_tbl_t *cmdtp, int flag,
82                         int argc, char *argv[],
83                         image_header_t *hdr,    /* of image to boot */
84                         int verify);            /* getenv("verify")[0] != 'n' */
85
86 extern boot_os_fn do_bootm_linux;
87 static boot_os_fn do_bootm_netbsd;
88 #if defined(CONFIG_LYNXKDI)
89 static boot_os_fn do_bootm_lynxkdi;
90 extern void lynxkdi_boot (image_header_t *);
91 #endif
92 static boot_os_fn do_bootm_rtems;
93 #if defined(CONFIG_CMD_ELF)
94 static boot_os_fn do_bootm_vxworks;
95 static boot_os_fn do_bootm_qnxelf;
96 int do_bootvx (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
97 int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
98 #endif
99 #if defined(CONFIG_ARTOS) && defined(CONFIG_PPC)
100 extern uchar (*env_get_char)(int); /* Returns a character from the environment */
101 static boot_os_fn do_bootm_artos;
102 #endif
103
104 ulong load_addr = CFG_LOAD_ADDR;        /* Default Load Address */
105
106
107 /*******************************************************************/
108 /* bootm - boot application image from image in memory */
109 /*******************************************************************/
110 int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
111 {
112         ulong           iflag;
113         const char      *type_name;
114         uint            unc_len = CFG_BOOTM_LEN;
115         int             verify = getenv_verify();
116
117         image_header_t  *hdr;
118         ulong           os_data, os_len;
119
120         ulong           image_start, image_end;
121         ulong           load_start, load_end;
122
123         /* get kernel image header, start address and length */
124         hdr = get_kernel (cmdtp, flag, argc, argv, verify,
125                         &os_data, &os_len);
126         if (hdr == NULL)
127                 return 1;
128
129         show_boot_progress (6);
130
131         /*
132          * We have reached the point of no return: we are going to
133          * overwrite all exception vector code, so we cannot easily
134          * recover from any failures any more...
135          */
136         iflag = disable_interrupts();
137
138 #ifdef CONFIG_AMIGAONEG3SE
139         /*
140          * We've possible left the caches enabled during
141          * bios emulation, so turn them off again
142          */
143         icache_disable();
144         invalidate_l1_instruction_cache();
145         flush_data_cache();
146         dcache_disable();
147 #endif
148
149         type_name = image_get_type_name (image_get_type (hdr));
150
151         image_start = (ulong)hdr;
152         image_end = image_get_image_end (hdr);
153         load_start = image_get_load (hdr);
154         load_end = 0;
155
156         switch (image_get_comp (hdr)) {
157         case IH_COMP_NONE:
158                 if (image_get_load (hdr) == (ulong)hdr) {
159                         printf ("   XIP %s ... ", type_name);
160                 } else {
161                         printf ("   Loading %s ... ", type_name);
162
163                         memmove_wd ((void *)image_get_load (hdr),
164                                    (void *)os_data, os_len, CHUNKSZ);
165
166                         load_end = load_start + os_len;
167                         puts("OK\n");
168                 }
169                 break;
170         case IH_COMP_GZIP:
171                 printf ("   Uncompressing %s ... ", type_name);
172                 if (gunzip ((void *)image_get_load (hdr), unc_len,
173                                         (uchar *)os_data, &os_len) != 0) {
174                         puts ("GUNZIP ERROR - must RESET board to recover\n");
175                         show_boot_progress (-6);
176                         do_reset (cmdtp, flag, argc, argv);
177                 }
178
179                 load_end = load_start + os_len;
180                 break;
181 #ifdef CONFIG_BZIP2
182         case IH_COMP_BZIP2:
183                 printf ("   Uncompressing %s ... ", type_name);
184                 /*
185                  * If we've got less than 4 MB of malloc() space,
186                  * use slower decompression algorithm which requires
187                  * at most 2300 KB of memory.
188                  */
189                 int i = BZ2_bzBuffToBuffDecompress ((char*)image_get_load (hdr),
190                                         &unc_len, (char *)os_data, os_len,
191                                         CFG_MALLOC_LEN < (4096 * 1024), 0);
192                 if (i != BZ_OK) {
193                         printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i);
194                         show_boot_progress (-6);
195                         do_reset (cmdtp, flag, argc, argv);
196                 }
197
198                 load_end = load_start + unc_len;
199                 break;
200 #endif /* CONFIG_BZIP2 */
201         default:
202                 if (iflag)
203                         enable_interrupts();
204                 printf ("Unimplemented compression type %d\n", image_get_comp (hdr));
205                 show_boot_progress (-7);
206                 return 1;
207         }
208         puts ("OK\n");
209         debug ("   kernel loaded at 0x%08lx, end = 0x%08lx\n", load_start, load_end);
210         show_boot_progress (7);
211
212         if ((load_start < image_end) && (load_end > image_start)) {
213                 debug ("image_start = 0x%lX, image_end = 0x%lx\n", image_start, image_end);
214                 debug ("load_start = 0x%lx, load_end = 0x%lx\n", load_start, load_end);
215
216                 puts ("ERROR: image overwritten - must RESET the board to recover.\n");
217                 do_reset (cmdtp, flag, argc, argv);
218         }
219
220         show_boot_progress (8);
221
222         switch (image_get_os (hdr)) {
223         default:                        /* handled by (original) Linux case */
224         case IH_OS_LINUX:
225 #ifdef CONFIG_SILENT_CONSOLE
226             fixup_silent_linux();
227 #endif
228             do_bootm_linux (cmdtp, flag, argc, argv, hdr, verify);
229             break;
230
231         case IH_OS_NETBSD:
232             do_bootm_netbsd (cmdtp, flag, argc, argv, hdr, verify);
233             break;
234
235 #ifdef CONFIG_LYNXKDI
236         case IH_OS_LYNXOS:
237             do_bootm_lynxkdi (cmdtp, flag, argc, argv, hdr, verify);
238             break;
239 #endif
240
241         case IH_OS_RTEMS:
242             do_bootm_rtems (cmdtp, flag, argc, argv, hdr, verify);
243             break;
244
245 #if defined(CONFIG_CMD_ELF)
246         case IH_OS_VXWORKS:
247             do_bootm_vxworks (cmdtp, flag, argc, argv, hdr, verify);
248             break;
249
250         case IH_OS_QNX:
251             do_bootm_qnxelf (cmdtp, flag, argc, argv, hdr, verify);
252             break;
253 #endif
254
255 #ifdef CONFIG_ARTOS
256         case IH_OS_ARTOS:
257             do_bootm_artos (cmdtp, flag, argc, argv, hdr, verify);
258             break;
259 #endif
260         }
261
262         show_boot_progress (-9);
263 #ifdef DEBUG
264         puts ("\n## Control returned to monitor - resetting...\n");
265         do_reset (cmdtp, flag, argc, argv);
266 #endif
267         return 1;
268 }
269
270 /**
271  * get_kernel - find kernel image
272  * @os_data: pointer to a ulong variable, will hold os data start address
273  * @os_len: pointer to a ulong variable, will hold os data length
274  *
275  * get_kernel() tries to find a kernel image, verifies its integrity
276  * and locates kernel data.
277  *
278  * returns:
279  *     pointer to image header if valid image was found, plus kernel start
280  *     address and length, otherwise NULL
281  */
282 static image_header_t *get_kernel (cmd_tbl_t *cmdtp, int flag,
283                 int argc, char *argv[], int verify,
284                 ulong *os_data, ulong *os_len)
285 {
286         image_header_t  *hdr;
287         ulong           img_addr;
288
289         if (argc < 2) {
290                 img_addr = load_addr;
291         } else {
292                 img_addr = simple_strtoul(argv[1], NULL, 16);
293         }
294
295         show_boot_progress (1);
296         printf ("## Booting image at %08lx ...\n", img_addr);
297
298         /* copy from dataflash if needed */
299         img_addr = gen_get_image (img_addr);
300         hdr = (image_header_t *)img_addr;
301
302         if (!image_check_magic(hdr)) {
303                 puts ("Bad Magic Number\n");
304                 show_boot_progress (-1);
305                 return NULL;
306         }
307         show_boot_progress (2);
308
309         if (!image_check_hcrc (hdr)) {
310                 puts ("Bad Header Checksum\n");
311                 show_boot_progress (-2);
312                 return NULL;
313         }
314
315         show_boot_progress (3);
316         image_print_contents (hdr);
317
318         if (verify) {
319                 puts ("   Verifying Checksum ... ");
320                 if (!image_check_dcrc (hdr)) {
321                         printf ("Bad Data CRC\n");
322                         show_boot_progress (-3);
323                         return NULL;
324                 }
325                 puts ("OK\n");
326         }
327         show_boot_progress (4);
328
329         if (!image_check_target_arch (hdr)) {
330                 printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));
331                 show_boot_progress (-4);
332                 return NULL;
333         }
334         show_boot_progress (5);
335
336         switch (image_get_type (hdr)) {
337         case IH_TYPE_KERNEL:
338                 *os_data = image_get_data (hdr);
339                 *os_len = image_get_data_size (hdr);
340                 break;
341         case IH_TYPE_MULTI:
342                 image_multi_getimg (hdr, 0, os_data, os_len);
343                 break;
344         default:
345                 printf ("Wrong Image Type for %s command\n", cmdtp->name);
346                 show_boot_progress (-5);
347                 return NULL;
348         }
349         debug ("   kernel data at 0x%08lx, end = 0x%08lx\n",
350                         *os_data, *os_data + *os_len);
351
352         return hdr;
353 }
354
355 U_BOOT_CMD(
356         bootm,  CFG_MAXARGS,    1,      do_bootm,
357         "bootm   - boot application image from memory\n",
358         "[addr [arg ...]]\n    - boot application image stored in memory\n"
359         "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
360         "\t'arg' can be the address of an initrd image\n"
361 #if defined(CONFIG_OF_LIBFDT)
362         "\tWhen booting a Linux kernel which requires a flat device-tree\n"
363         "\ta third argument is required which is the address of the\n"
364         "\tdevice-tree blob. To boot that kernel without an initrd image,\n"
365         "\tuse a '-' for the second argument. If you do not pass a third\n"
366         "\ta bd_info struct will be passed instead\n"
367 #endif
368 );
369
370 /*******************************************************************/
371 /* bootd - boot default image */
372 /*******************************************************************/
373 #if defined(CONFIG_CMD_BOOTD)
374 int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
375 {
376         int rcode = 0;
377
378 #ifndef CFG_HUSH_PARSER
379         if (run_command (getenv ("bootcmd"), flag) < 0)
380                 rcode = 1;
381 #else
382         if (parse_string_outer (getenv ("bootcmd"),
383                         FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
384                 rcode = 1;
385 #endif
386         return rcode;
387 }
388
389 U_BOOT_CMD(
390         boot,   1,      1,      do_bootd,
391         "boot    - boot default, i.e., run 'bootcmd'\n",
392         NULL
393 );
394
395 /* keep old command name "bootd" for backward compatibility */
396 U_BOOT_CMD(
397         bootd, 1,       1,      do_bootd,
398         "bootd   - boot default, i.e., run 'bootcmd'\n",
399         NULL
400 );
401
402 #endif
403
404
405 /*******************************************************************/
406 /* iminfo - print header info for a requested image */
407 /*******************************************************************/
408 #if defined(CONFIG_CMD_IMI)
409 int do_iminfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
410 {
411         int     arg;
412         ulong   addr;
413         int     rcode = 0;
414
415         if (argc < 2) {
416                 return image_info (load_addr);
417         }
418
419         for (arg = 1; arg < argc; ++arg) {
420                 addr = simple_strtoul (argv[arg], NULL, 16);
421                 if (image_info (addr) != 0)
422                         rcode = 1;
423         }
424         return rcode;
425 }
426
427 static int image_info (ulong addr)
428 {
429         image_header_t *hdr = (image_header_t *)addr;
430
431         printf ("\n## Checking Image at %08lx ...\n", addr);
432
433         if (!image_check_magic (hdr)) {
434                 puts ("   Bad Magic Number\n");
435                 return 1;
436         }
437
438         if (!image_check_hcrc (hdr)) {
439                 puts ("   Bad Header Checksum\n");
440                 return 1;
441         }
442
443         image_print_contents (hdr);
444
445         puts ("   Verifying Checksum ... ");
446         if (!image_check_dcrc (hdr)) {
447                 puts ("   Bad Data CRC\n");
448                 return 1;
449         }
450         puts ("OK\n");
451         return 0;
452 }
453
454 U_BOOT_CMD(
455         iminfo, CFG_MAXARGS,    1,      do_iminfo,
456         "iminfo  - print header information for application image\n",
457         "addr [addr ...]\n"
458         "    - print header information for application image starting at\n"
459         "      address 'addr' in memory; this includes verification of the\n"
460         "      image contents (magic number, header and payload checksums)\n"
461 );
462 #endif
463
464
465 /*******************************************************************/
466 /* imls - list all images found in flash */
467 /*******************************************************************/
468 #if defined(CONFIG_CMD_IMLS)
469 int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
470 {
471         flash_info_t *info;
472         int i, j;
473         image_header_t *hdr;
474
475         for (i = 0, info = &flash_info[0];
476                 i < CFG_MAX_FLASH_BANKS; ++i, ++info) {
477
478                 if (info->flash_id == FLASH_UNKNOWN)
479                         goto next_bank;
480                 for (j = 0; j < info->sector_count; ++j) {
481
482                         hdr = (image_header_t *)info->start[j];
483
484                         if (!hdr || !image_check_magic (hdr))
485                                 goto next_sector;
486
487                         if (!image_check_hcrc (hdr))
488                                 goto next_sector;
489
490                         printf ("Image at %08lX:\n", (ulong)hdr);
491                         image_print_contents (hdr);
492
493                         puts ("   Verifying Checksum ... ");
494                         if (!image_check_dcrc (hdr)) {
495                                 puts ("Bad Data CRC\n");
496                         } else {
497                                 puts ("OK\n");
498                         }
499 next_sector:            ;
500                 }
501 next_bank:      ;
502         }
503
504         return (0);
505 }
506
507 U_BOOT_CMD(
508         imls,   1,              1,      do_imls,
509         "imls    - list all images found in flash\n",
510         "\n"
511         "    - Prints information about all images found at sector\n"
512         "      boundaries in flash.\n"
513 );
514 #endif
515
516 /*******************************************************************/
517 /* helper routines */
518 /*******************************************************************/
519 #ifdef CONFIG_SILENT_CONSOLE
520 static void fixup_silent_linux ()
521 {
522         char buf[256], *start, *end;
523         char *cmdline = getenv ("bootargs");
524
525         /* Only fix cmdline when requested */
526         if (!(gd->flags & GD_FLG_SILENT))
527                 return;
528
529         debug ("before silent fix-up: %s\n", cmdline);
530         if (cmdline) {
531                 if ((start = strstr (cmdline, "console=")) != NULL) {
532                         end = strchr (start, ' ');
533                         strncpy (buf, cmdline, (start - cmdline + 8));
534                         if (end)
535                                 strcpy (buf + (start - cmdline + 8), end);
536                         else
537                                 buf[start - cmdline + 8] = '\0';
538                 } else {
539                         strcpy (buf, cmdline);
540                         strcat (buf, " console=");
541                 }
542         } else {
543                 strcpy (buf, "console=");
544         }
545
546         setenv ("bootargs", buf);
547         debug ("after silent fix-up: %s\n", buf);
548 }
549 #endif /* CONFIG_SILENT_CONSOLE */
550
551
552 /*******************************************************************/
553 /* OS booting routines */
554 /*******************************************************************/
555
556 static void do_bootm_netbsd (cmd_tbl_t *cmdtp, int flag,
557                             int argc, char *argv[],
558                             image_header_t *hdr, int verify)
559 {
560         void (*loader)(bd_t *, image_header_t *, char *, char *);
561         image_header_t *img_addr;
562         ulong kernel_data, kernel_len;
563         char *consdev;
564         char *cmdline;
565
566         /*
567          * Booting a (NetBSD) kernel image
568          *
569          * This process is pretty similar to a standalone application:
570          * The (first part of an multi-) image must be a stage-2 loader,
571          * which in turn is responsible for loading & invoking the actual
572          * kernel.  The only differences are the parameters being passed:
573          * besides the board info strucure, the loader expects a command
574          * line, the name of the console device, and (optionally) the
575          * address of the original image header.
576          */
577
578         img_addr = 0;
579         if (image_check_type (hdr, IH_TYPE_MULTI)) {
580                 image_multi_getimg (hdr, 1, &kernel_data, &kernel_len);
581                 if (kernel_len)
582                         img_addr = hdr;
583         }
584
585         consdev = "";
586 #if   defined (CONFIG_8xx_CONS_SMC1)
587         consdev = "smc1";
588 #elif defined (CONFIG_8xx_CONS_SMC2)
589         consdev = "smc2";
590 #elif defined (CONFIG_8xx_CONS_SCC2)
591         consdev = "scc2";
592 #elif defined (CONFIG_8xx_CONS_SCC3)
593         consdev = "scc3";
594 #endif
595
596         if (argc > 2) {
597                 ulong len;
598                 int   i;
599
600                 for (i = 2, len = 0; i < argc; i += 1)
601                         len += strlen (argv[i]) + 1;
602                 cmdline = malloc (len);
603
604                 for (i = 2, len = 0; i < argc; i += 1) {
605                         if (i > 2)
606                                 cmdline[len++] = ' ';
607                         strcpy (&cmdline[len], argv[i]);
608                         len += strlen (argv[i]);
609                 }
610         } else if ((cmdline = getenv ("bootargs")) == NULL) {
611                 cmdline = "";
612         }
613
614         loader = (void (*)(bd_t *, image_header_t *, char *, char *))image_get_ep (hdr);
615
616         printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
617                 (ulong)loader);
618
619         show_boot_progress (15);
620
621         /*
622          * NetBSD Stage-2 Loader Parameters:
623          *   r3: ptr to board info data
624          *   r4: image address
625          *   r5: console device
626          *   r6: boot args string
627          */
628         (*loader) (gd->bd, img_addr, consdev, cmdline);
629 }
630
631 #ifdef CONFIG_LYNXKDI
632 static void do_bootm_lynxkdi (cmd_tbl_t *cmdtp, int flag,
633                              int argc, char *argv[],
634                              image_header_t *hdr, int verify)
635 {
636         lynxkdi_boot (hdr);
637 }
638 #endif /* CONFIG_LYNXKDI */
639
640 static void do_bootm_rtems (cmd_tbl_t *cmdtp, int flag,
641                            int argc, char *argv[],
642                            image_header_t *hdr, int verify)
643 {
644         void (*entry_point)(bd_t *);
645
646         entry_point = (void (*)(bd_t *))image_get_ep (hdr);
647
648         printf ("## Transferring control to RTEMS (at address %08lx) ...\n",
649                 (ulong)entry_point);
650
651         show_boot_progress (15);
652
653         /*
654          * RTEMS Parameters:
655          *   r3: ptr to board info data
656          */
657         (*entry_point)(gd->bd);
658 }
659
660 #if defined(CONFIG_CMD_ELF)
661 static void do_bootm_vxworks (cmd_tbl_t *cmdtp, int flag,
662                              int argc, char *argv[],
663                              image_header_t *hdr, int verify)
664 {
665         char str[80];
666
667         sprintf(str, "%x", image_get_ep (hdr)); /* write entry-point into string */
668         setenv("loadaddr", str);
669         do_bootvx(cmdtp, 0, 0, NULL);
670 }
671
672 static void do_bootm_qnxelf(cmd_tbl_t *cmdtp, int flag,
673                             int argc, char *argv[],
674                             image_header_t *hdr, int verify)
675 {
676         char *local_args[2];
677         char str[16];
678
679         sprintf(str, "%x", image_get_ep (hdr)); /* write entry-point into string */
680         local_args[0] = argv[0];
681         local_args[1] = str;    /* and provide it via the arguments */
682         do_bootelf(cmdtp, 0, 2, local_args);
683 }
684 #endif
685
686 #if defined(CONFIG_ARTOS) && defined(CONFIG_PPC)
687 static void do_bootm_artos (cmd_tbl_t *cmdtp, int flag,
688                            int argc, char *argv[],
689                            image_header_t *hdr, int verify)
690 {
691         ulong top;
692         char *s, *cmdline;
693         char **fwenv, **ss;
694         int i, j, nxt, len, envno, envsz;
695         bd_t *kbd;
696         void (*entry)(bd_t *bd, char *cmdline, char **fwenv, ulong top);
697
698         /*
699          * Booting an ARTOS kernel image + application
700          */
701
702         /* this used to be the top of memory, but was wrong... */
703 #ifdef CONFIG_PPC
704         /* get stack pointer */
705         asm volatile ("mr %0,1" : "=r"(top) );
706 #endif
707         debug ("## Current stack ends at 0x%08lX ", top);
708
709         top -= 2048;            /* just to be sure */
710         if (top > CFG_BOOTMAPSZ)
711                 top = CFG_BOOTMAPSZ;
712         top &= ~0xF;
713
714         debug ("=> set upper limit to 0x%08lX\n", top);
715
716         /* first check the artos specific boot args, then the linux args*/
717         if ((s = getenv( "abootargs")) == NULL && (s = getenv ("bootargs")) == NULL)
718                 s = "";
719
720         /* get length of cmdline, and place it */
721         len = strlen (s);
722         top = (top - (len + 1)) & ~0xF;
723         cmdline = (char *)top;
724         debug ("## cmdline at 0x%08lX ", top);
725         strcpy (cmdline, s);
726
727         /* copy bdinfo */
728         top = (top - sizeof (bd_t)) & ~0xF;
729         debug ("## bd at 0x%08lX ", top);
730         kbd = (bd_t *)top;
731         memcpy (kbd, gd->bd, sizeof (bd_t));
732
733         /* first find number of env entries, and their size */
734         envno = 0;
735         envsz = 0;
736         for (i = 0; env_get_char (i) != '\0'; i = nxt + 1) {
737                 for (nxt = i; env_get_char (nxt) != '\0'; ++nxt)
738                         ;
739                 envno++;
740                 envsz += (nxt - i) + 1; /* plus trailing zero */
741         }
742         envno++;        /* plus the terminating zero */
743         debug ("## %u envvars total size %u ", envno, envsz);
744
745         top = (top - sizeof (char **) * envno) & ~0xF;
746         fwenv = (char **)top;
747         debug ("## fwenv at 0x%08lX ", top);
748
749         top = (top - envsz) & ~0xF;
750         s = (char *)top;
751         ss = fwenv;
752
753         /* now copy them */
754         for (i = 0; env_get_char (i) != '\0'; i = nxt + 1) {
755                 for (nxt = i; env_get_char (nxt) != '\0'; ++nxt)
756                         ;
757                 *ss++ = s;
758                 for (j = i; j < nxt; ++j)
759                         *s++ = env_get_char (j);
760                 *s++ = '\0';
761         }
762         *ss++ = NULL;   /* terminate */
763
764         entry = (void (*)(bd_t *, char *, char **, ulong))image_get_ep (hdr);
765         (*entry) (kbd, cmdline, fwenv, top);
766 }
767 #endif