421a47453c6daf4168a7bdf0eddf8bc064f81fa4
[platform/kernel/u-boot.git] / common / image.c
1 /*
2  * (C) Copyright 2008 Semihalf
3  *
4  * (C) Copyright 2000-2006
5  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25
26 #define DEBUG
27
28 #ifndef USE_HOSTCC
29 #include <common.h>
30 #include <watchdog.h>
31
32 #ifdef CONFIG_SHOW_BOOT_PROGRESS
33 #include <status_led.h>
34 #endif
35
36 #ifdef CONFIG_HAS_DATAFLASH
37 #include <dataflash.h>
38 #endif
39
40 #ifdef CONFIG_LOGBUFFER
41 #include <logbuff.h>
42 #endif
43
44 #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE)
45 #include <rtc.h>
46 #endif
47
48 #if defined(CONFIG_FIT)
49 #include <fdt.h>
50 #include <libfdt.h>
51 #include <fdt_support.h>
52 #endif
53
54 #ifdef CONFIG_CMD_BDI
55 extern int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
56 #endif
57
58 DECLARE_GLOBAL_DATA_PTR;
59
60 static image_header_t* image_get_ramdisk (cmd_tbl_t *cmdtp, int flag,
61                 int argc, char *argv[],
62                 ulong rd_addr, uint8_t arch, int verify);
63 #else
64 #include "mkimage.h"
65 #endif /* !USE_HOSTCC*/
66
67 #include <image.h>
68
69 typedef struct table_entry {
70         int     id;             /* as defined in image.h        */
71         char    *sname;         /* short (input) name           */
72         char    *lname;         /* long (output) name           */
73 } table_entry_t;
74
75 static table_entry_t uimage_arch[] = {
76         {       IH_ARCH_INVALID,        NULL,           "Invalid ARCH", },
77         {       IH_ARCH_ALPHA,          "alpha",        "Alpha",        },
78         {       IH_ARCH_ARM,            "arm",          "ARM",          },
79         {       IH_ARCH_I386,           "x86",          "Intel x86",    },
80         {       IH_ARCH_IA64,           "ia64",         "IA64",         },
81         {       IH_ARCH_M68K,           "m68k",         "M68K",         },
82         {       IH_ARCH_MICROBLAZE,     "microblaze",   "MicroBlaze",   },
83         {       IH_ARCH_MIPS,           "mips",         "MIPS",         },
84         {       IH_ARCH_MIPS64,         "mips64",       "MIPS 64 Bit",  },
85         {       IH_ARCH_NIOS,           "nios",         "NIOS",         },
86         {       IH_ARCH_NIOS2,          "nios2",        "NIOS II",      },
87         {       IH_ARCH_PPC,            "ppc",          "PowerPC",      },
88         {       IH_ARCH_S390,           "s390",         "IBM S390",     },
89         {       IH_ARCH_SH,             "sh",           "SuperH",       },
90         {       IH_ARCH_SPARC,          "sparc",        "SPARC",        },
91         {       IH_ARCH_SPARC64,        "sparc64",      "SPARC 64 Bit", },
92         {       IH_ARCH_BLACKFIN,       "blackfin",     "Blackfin",     },
93         {       IH_ARCH_AVR32,          "avr32",        "AVR32",        },
94         {       -1,                     "",             "",             },
95 };
96
97 static table_entry_t uimage_os[] = {
98         {       IH_OS_INVALID,  NULL,           "Invalid OS",           },
99 #if defined(CONFIG_ARTOS) || defined(USE_HOSTCC)
100         {       IH_OS_ARTOS,    "artos",        "ARTOS",                },
101 #endif
102         {       IH_OS_LINUX,    "linux",        "Linux",                },
103 #if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC)
104         {       IH_OS_LYNXOS,   "lynxos",       "LynxOS",               },
105 #endif
106         {       IH_OS_NETBSD,   "netbsd",       "NetBSD",               },
107         {       IH_OS_RTEMS,    "rtems",        "RTEMS",                },
108         {       IH_OS_U_BOOT,   "u-boot",       "U-Boot",               },
109 #if defined(CONFIG_CMD_ELF) || defined(USE_HOSTCC)
110         {       IH_OS_QNX,      "qnx",          "QNX",                  },
111         {       IH_OS_VXWORKS,  "vxworks",      "VxWorks",              },
112 #endif
113 #ifdef USE_HOSTCC
114         {       IH_OS_4_4BSD,   "4_4bsd",       "4_4BSD",               },
115         {       IH_OS_DELL,     "dell",         "Dell",                 },
116         {       IH_OS_ESIX,     "esix",         "Esix",                 },
117         {       IH_OS_FREEBSD,  "freebsd",      "FreeBSD",              },
118         {       IH_OS_IRIX,     "irix",         "Irix",                 },
119         {       IH_OS_NCR,      "ncr",          "NCR",                  },
120         {       IH_OS_OPENBSD,  "openbsd",      "OpenBSD",              },
121         {       IH_OS_PSOS,     "psos",         "pSOS",                 },
122         {       IH_OS_SCO,      "sco",          "SCO",                  },
123         {       IH_OS_SOLARIS,  "solaris",      "Solaris",              },
124         {       IH_OS_SVR4,     "svr4",         "SVR4",                 },
125 #endif
126         {       -1,             "",             "",                     },
127 };
128
129 static table_entry_t uimage_type[] = {
130         {       IH_TYPE_INVALID,    NULL,         "Invalid Image",      },
131         {       IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image",   },
132         {       IH_TYPE_FIRMWARE,   "firmware",   "Firmware",           },
133         {       IH_TYPE_KERNEL,     "kernel",     "Kernel Image",       },
134         {       IH_TYPE_MULTI,      "multi",      "Multi-File Image",   },
135         {       IH_TYPE_RAMDISK,    "ramdisk",    "RAMDisk Image",      },
136         {       IH_TYPE_SCRIPT,     "script",     "Script",             },
137         {       IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
138         {       IH_TYPE_FLATDT,     "flat_dt",    "Flat Device Tree",   },
139         {       -1,                 "",           "",                   },
140 };
141
142 static table_entry_t uimage_comp[] = {
143         {       IH_COMP_NONE,   "none",         "uncompressed",         },
144         {       IH_COMP_BZIP2,  "bzip2",        "bzip2 compressed",     },
145         {       IH_COMP_GZIP,   "gzip",         "gzip compressed",      },
146         {       -1,             "",             "",                     },
147 };
148
149 unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
150 static void genimg_print_size (uint32_t size);
151 #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
152 static void genimg_print_time (time_t timestamp);
153 #endif
154
155 /*****************************************************************************/
156 /* Legacy format routines */
157 /*****************************************************************************/
158 int image_check_hcrc (image_header_t *hdr)
159 {
160         ulong hcrc;
161         ulong len = image_get_header_size ();
162         image_header_t header;
163
164         /* Copy header so we can blank CRC field for re-calculation */
165         memmove (&header, (char *)hdr, image_get_header_size ());
166         image_set_hcrc (&header, 0);
167
168         hcrc = crc32 (0, (unsigned char *)&header, len);
169
170         return (hcrc == image_get_hcrc (hdr));
171 }
172
173 int image_check_dcrc (image_header_t *hdr)
174 {
175         ulong data = image_get_data (hdr);
176         ulong len = image_get_data_size (hdr);
177         ulong dcrc = crc32 (0, (unsigned char *)data, len);
178
179         return (dcrc == image_get_dcrc (hdr));
180 }
181
182 #ifndef USE_HOSTCC
183 int image_check_dcrc_wd (image_header_t *hdr, ulong chunksz)
184 {
185         ulong dcrc = 0;
186         ulong len = image_get_data_size (hdr);
187         ulong data = image_get_data (hdr);
188
189 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
190         ulong cdata = data;
191         ulong edata = cdata + len;
192
193         while (cdata < edata) {
194                 ulong chunk = edata - cdata;
195
196                 if (chunk > chunksz)
197                         chunk = chunksz;
198                 dcrc = crc32 (dcrc, (unsigned char *)cdata, chunk);
199                 cdata += chunk;
200
201                 WATCHDOG_RESET ();
202         }
203 #else
204         dcrc = crc32 (0, (unsigned char *)data, len);
205 #endif
206
207         return (dcrc == image_get_dcrc (hdr));
208 }
209 #endif /* !USE_HOSTCC */
210
211 /**
212  * image_multi_count - get component (sub-image) count
213  * @hdr: pointer to the header of the multi component image
214  *
215  * image_multi_count() returns number of components in a multi
216  * component image.
217  *
218  * Note: no checking of the image type is done, caller must pass
219  * a valid multi component image.
220  *
221  * returns:
222  *     number of components
223  */
224 ulong image_multi_count (image_header_t *hdr)
225 {
226         ulong i, count = 0;
227         ulong *size;
228
229         /* get start of the image payload, which in case of multi
230          * component images that points to a table of component sizes */
231         size = (ulong *)image_get_data (hdr);
232
233         /* count non empty slots */
234         for (i = 0; size[i]; ++i)
235                 count++;
236
237         return count;
238 }
239
240 /**
241  * image_multi_getimg - get component data address and size
242  * @hdr: pointer to the header of the multi component image
243  * @idx: index of the requested component
244  * @data: pointer to a ulong variable, will hold component data address
245  * @len: pointer to a ulong variable, will hold component size
246  *
247  * image_multi_getimg() returns size and data address for the requested
248  * component in a multi component image.
249  *
250  * Note: no checking of the image type is done, caller must pass
251  * a valid multi component image.
252  *
253  * returns:
254  *     data address and size of the component, if idx is valid
255  *     0 in data and len, if idx is out of range
256  */
257 void image_multi_getimg (image_header_t *hdr, ulong idx,
258                         ulong *data, ulong *len)
259 {
260         int i;
261         ulong *size;
262         ulong offset, tail, count, img_data;
263
264         /* get number of component */
265         count = image_multi_count (hdr);
266
267         /* get start of the image payload, which in case of multi
268          * component images that points to a table of component sizes */
269         size = (ulong *)image_get_data (hdr);
270
271         /* get address of the proper component data start, which means
272          * skipping sizes table (add 1 for last, null entry) */
273         img_data = image_get_data (hdr) + (count + 1) * sizeof (ulong);
274
275         if (idx < count) {
276                 *len = size[idx];
277                 offset = 0;
278                 tail = 0;
279
280                 /* go over all indices preceding requested component idx */
281                 for (i = 0; i < idx; i++) {
282                         /* add up i-th component size */
283                         offset += size[i];
284
285                         /* add up alignment for i-th component */
286                         tail += (4 - size[i] % 4);
287                 }
288
289                 /* calculate idx-th component data address */
290                 *data = img_data + offset + tail;
291         } else {
292                 *len = 0;
293                 *data = 0;
294         }
295 }
296
297 static void image_print_type (image_header_t *hdr)
298 {
299         const char *os, *arch, *type, *comp;
300
301         os = genimg_get_os_name (image_get_os (hdr));
302         arch = genimg_get_arch_name (image_get_arch (hdr));
303         type = genimg_get_type_name (image_get_type (hdr));
304         comp = genimg_get_comp_name (image_get_comp (hdr));
305
306         printf ("%s %s %s (%s)\n", arch, os, type, comp);
307 }
308
309 static void __image_print_contents (image_header_t *hdr, const char *p)
310 {
311         printf ("%sImage Name:   %.*s\n", p, IH_NMLEN, image_get_name (hdr));
312 #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
313         printf ("%sCreated:      ", p);
314         genimg_print_time ((time_t)image_get_time (hdr));
315 #endif
316         printf ("%sImage Type:   ", p);
317         image_print_type (hdr);
318         printf ("%sData Size:    ", p);
319         genimg_print_size (image_get_data_size (hdr));
320         printf ("%sLoad Address: %08x\n", p, image_get_load (hdr));
321         printf ("%sEntry Point:  %08x\n", p, image_get_ep (hdr));
322
323         if (image_check_type (hdr, IH_TYPE_MULTI) ||
324                         image_check_type (hdr, IH_TYPE_SCRIPT)) {
325                 int i;
326                 ulong data, len;
327                 ulong count = image_multi_count (hdr);
328
329                 printf ("%sContents:\n", p);
330                 for (i = 0; i < count; i++) {
331                         image_multi_getimg (hdr, i, &data, &len);
332
333                         printf ("%s   Image %d: ", p, i);
334                         genimg_print_size (len);
335
336                         if (image_check_type (hdr, IH_TYPE_SCRIPT) && i > 0) {
337                                 /*
338                                  * the user may need to know offsets
339                                  * if planning to do something with
340                                  * multiple files
341                                  */
342                                 printf ("%s    Offset = 0x%08lx\n", p, data);
343                         }
344                 }
345         }
346 }
347
348 inline void image_print_contents (image_header_t *hdr)
349 {
350         __image_print_contents (hdr, "   ");
351 }
352
353 inline void image_print_contents_noindent (image_header_t *hdr)
354 {
355         __image_print_contents (hdr, "");
356 }
357
358 #ifndef USE_HOSTCC
359 /**
360  * image_get_ramdisk - get and verify ramdisk image
361  * @cmdtp: command table pointer
362  * @flag: command flag
363  * @argc: command argument count
364  * @argv: command argument list
365  * @rd_addr: ramdisk image start address
366  * @arch: expected ramdisk architecture
367  * @verify: checksum verification flag
368  *
369  * image_get_ramdisk() returns a pointer to the verified ramdisk image
370  * header. Routine receives image start address and expected architecture
371  * flag. Verification done covers data and header integrity and os/type/arch
372  * fields checking.
373  *
374  * If dataflash support is enabled routine checks for dataflash addresses
375  * and handles required dataflash reads.
376  *
377  * returns:
378  *     pointer to a ramdisk image header, if image was found and valid
379  *     otherwise, return NULL
380  */
381 static image_header_t* image_get_ramdisk (cmd_tbl_t *cmdtp, int flag,
382                 int argc, char *argv[],
383                 ulong rd_addr, uint8_t arch, int verify)
384 {
385         image_header_t *rd_hdr;
386
387         show_boot_progress (9);
388         rd_hdr = (image_header_t *)rd_addr;
389
390         if (!image_check_magic (rd_hdr)) {
391                 puts ("Bad Magic Number\n");
392                 show_boot_progress (-10);
393                 return NULL;
394         }
395
396         if (!image_check_hcrc (rd_hdr)) {
397                 puts ("Bad Header Checksum\n");
398                 show_boot_progress (-11);
399                 return NULL;
400         }
401
402         show_boot_progress (10);
403         image_print_contents (rd_hdr);
404
405         if (verify) {
406                 puts("   Verifying Checksum ... ");
407                 if (!image_check_dcrc_wd (rd_hdr, CHUNKSZ)) {
408                         puts ("Bad Data CRC\n");
409                         show_boot_progress (-12);
410                         return NULL;
411                 }
412                 puts("OK\n");
413         }
414
415         show_boot_progress (11);
416
417         if (!image_check_os (rd_hdr, IH_OS_LINUX) ||
418             !image_check_arch (rd_hdr, arch) ||
419             !image_check_type (rd_hdr, IH_TYPE_RAMDISK)) {
420                 printf ("No Linux %s Ramdisk Image\n",
421                                 genimg_get_arch_name(arch));
422                 show_boot_progress (-13);
423                 return NULL;
424         }
425
426         return rd_hdr;
427 }
428 #endif /* !USE_HOSTCC */
429
430 /*****************************************************************************/
431 /* Shared dual-format routines */
432 /*****************************************************************************/
433 #ifndef USE_HOSTCC
434 int getenv_verify (void)
435 {
436         char *s = getenv ("verify");
437         return (s && (*s == 'n')) ? 0 : 1;
438 }
439
440 int getenv_autostart (void)
441 {
442         char *s = getenv ("autostart");
443         return (s && (*s == 'n')) ? 0 : 1;
444 }
445
446 ulong getenv_bootm_low(void)
447 {
448         char *s = getenv ("bootm_low");
449         if (s) {
450                 ulong tmp = simple_strtoul (s, NULL, 16);
451                 return tmp;
452         }
453
454 #ifdef CFG_SDRAM_BASE
455         return CFG_SDRAM_BASE;
456 #else
457         return 0;
458 #endif
459 }
460
461 ulong getenv_bootm_size(void)
462 {
463         char *s = getenv ("bootm_size");
464         if (s) {
465                 ulong tmp = simple_strtoul (s, NULL, 16);
466                 return tmp;
467         }
468
469         return gd->bd->bi_memsize;
470 }
471
472 void memmove_wd (void *to, void *from, size_t len, ulong chunksz)
473 {
474 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
475         while (len > 0) {
476                 size_t tail = (len > chunksz) ? chunksz : len;
477                 WATCHDOG_RESET ();
478                 memmove (to, from, tail);
479                 to += tail;
480                 from += tail;
481                 len -= tail;
482         }
483 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
484         memmove (to, from, len);
485 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
486 }
487 #endif /* !USE_HOSTCC */
488
489 static void genimg_print_size (uint32_t size)
490 {
491 #ifndef USE_HOSTCC
492         printf ("%d Bytes = ", size);
493         print_size (size, "\n");
494 #else
495         printf ("%d Bytes = %.2f kB = %.2f MB\n",
496                         size, (double)size / 1.024e3,
497                         (double)size / 1.048576e6);
498 #endif
499 }
500
501 #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
502 static void genimg_print_time (time_t timestamp)
503 {
504 #ifndef USE_HOSTCC
505         struct rtc_time tm;
506
507         to_tm (timestamp, &tm);
508         printf ("%4d-%02d-%02d  %2d:%02d:%02d UTC\n",
509                         tm.tm_year, tm.tm_mon, tm.tm_mday,
510                         tm.tm_hour, tm.tm_min, tm.tm_sec);
511 #else
512         printf ("%s", ctime(&timestamp));
513 #endif
514 }
515 #endif /* CONFIG_TIMESTAMP || CONFIG_CMD_DATE || USE_HOSTCC */
516
517 /**
518  * get_table_entry_name - translate entry id to long name
519  * @table: pointer to a translation table for entries of a specific type
520  * @msg: message to be returned when translation fails
521  * @id: entry id to be translated
522  *
523  * get_table_entry_name() will go over translation table trying to find
524  * entry that matches given id. If matching entry is found, its long
525  * name is returned to the caller.
526  *
527  * returns:
528  *     long entry name if translation succeeds
529  *     msg otherwise
530  */
531 static char *get_table_entry_name (table_entry_t *table, char *msg, int id)
532 {
533         for (; table->id >= 0; ++table) {
534                 if (table->id == id)
535                         return (table->lname);
536         }
537         return (msg);
538 }
539
540 const char *genimg_get_os_name (uint8_t os)
541 {
542         return (get_table_entry_name (uimage_os, "Unknown OS", os));
543 }
544
545 const char *genimg_get_arch_name (uint8_t arch)
546 {
547         return (get_table_entry_name (uimage_arch, "Unknown Architecture", arch));
548 }
549
550 const char *genimg_get_type_name (uint8_t type)
551 {
552         return (get_table_entry_name (uimage_type, "Unknown Image", type));
553 }
554
555 const char *genimg_get_comp_name (uint8_t comp)
556 {
557         return (get_table_entry_name (uimage_comp, "Unknown Compression", comp));
558 }
559
560 /**
561  * get_table_entry_id - translate short entry name to id
562  * @table: pointer to a translation table for entries of a specific type
563  * @table_name: to be used in case of error
564  * @name: entry short name to be translated
565  *
566  * get_table_entry_id() will go over translation table trying to find
567  * entry that matches given short name. If matching entry is found,
568  * its id returned to the caller.
569  *
570  * returns:
571  *     entry id if translation succeeds
572  *     -1 otherwise
573  */
574 static int get_table_entry_id (table_entry_t *table,
575                 const char *table_name, const char *name)
576 {
577         table_entry_t *t;
578 #ifdef USE_HOSTCC
579         int first = 1;
580
581         for (t = table; t->id >= 0; ++t) {
582                 if (t->sname && strcasecmp(t->sname, name) == 0)
583                         return (t->id);
584         }
585
586         fprintf (stderr, "\nInvalid %s Type - valid names are", table_name);
587         for (t = table; t->id >= 0; ++t) {
588                 if (t->sname == NULL)
589                         continue;
590                 fprintf (stderr, "%c %s", (first) ? ':' : ',', t->sname);
591                 first = 0;
592         }
593         fprintf (stderr, "\n");
594 #else
595         for (t = table; t->id >= 0; ++t) {
596                 if (t->sname && strcmp(t->sname, name) == 0)
597                         return (t->id);
598         }
599         debug ("Invalid %s Type: %s\n", table_name, name);
600 #endif /* USE_HOSTCC */
601         return (-1);
602 }
603
604 int genimg_get_os_id (const char *name)
605 {
606         return (get_table_entry_id (uimage_os, "OS", name));
607 }
608
609 int genimg_get_arch_id (const char *name)
610 {
611         return (get_table_entry_id (uimage_arch, "CPU", name));
612 }
613
614 int genimg_get_type_id (const char *name)
615 {
616         return (get_table_entry_id (uimage_type, "Image", name));
617 }
618
619 int genimg_get_comp_id (const char *name)
620 {
621         return (get_table_entry_id (uimage_comp, "Compression", name));
622 }
623
624 #ifndef USE_HOSTCC
625 /**
626  * genimg_get_format - get image format type
627  * @img_addr: image start address
628  *
629  * genimg_get_format() checks whether provided address points to a valid
630  * legacy or FIT image.
631  *
632  * New uImage format and FDT blob are based on a libfdt. FDT blob
633  * may be passed directly or embedded in a FIT image. In both situations
634  * genimg_get_format() must be able to dectect libfdt header.
635  *
636  * returns:
637  *     image format type or IMAGE_FORMAT_INVALID if no image is present
638  */
639 int genimg_get_format (void *img_addr)
640 {
641         ulong           format = IMAGE_FORMAT_INVALID;
642         image_header_t  *hdr;
643 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
644         char            *fit_hdr;
645 #endif
646
647         hdr = (image_header_t *)img_addr;
648         if (image_check_magic(hdr))
649                 format = IMAGE_FORMAT_LEGACY;
650 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
651         else {
652                 fit_hdr = (char *)img_addr;
653                 if (fdt_check_header (fit_hdr) == 0)
654                         format = IMAGE_FORMAT_FIT;
655         }
656 #endif
657
658         return format;
659 }
660
661 /**
662  * genimg_get_image - get image from special storage (if necessary)
663  * @img_addr: image start address
664  *
665  * genimg_get_image() checks if provided image start adddress is located
666  * in a dataflash storage. If so, image is moved to a system RAM memory.
667  *
668  * returns:
669  *     image start address after possible relocation from special storage
670  */
671 ulong genimg_get_image (ulong img_addr)
672 {
673         ulong ram_addr = img_addr;
674
675 #ifdef CONFIG_HAS_DATAFLASH
676         ulong h_size, d_size;
677
678         if (addr_dataflash (img_addr)){
679                 /* ger RAM address */
680                 ram_addr = CFG_LOAD_ADDR;
681
682                 /* get header size */
683                 h_size = image_get_header_size ();
684 #if defined(CONFIG_FIT)
685                 if (sizeof(struct fdt_header) > h_size)
686                         h_size = sizeof(struct fdt_header);
687 #endif
688
689                 /* read in header */
690                 debug ("   Reading image header from dataflash address "
691                         "%08lx to RAM address %08lx\n", img_addr, ram_addr);
692
693                 read_dataflash (img_addr, h_size, (char *)ram_addr);
694
695                 /* get data size */
696                 switch (genimg_get_format ((void *)ram_addr)) {
697                 case IMAGE_FORMAT_LEGACY:
698                         d_size = image_get_data_size ((image_header_t *)ram_addr);
699                         debug ("   Legacy format image found at 0x%08lx, size 0x%08lx\n",
700                                         ram_addr, d_size);
701                         break;
702 #if defined(CONFIG_FIT)
703                 case IMAGE_FORMAT_FIT:
704                         d_size = fdt_totalsize((void *)ram_addr) - h_size;
705                         debug ("   FIT/FDT format image found at 0x%08lx, size 0x%08lx\n",
706                                         ram_addr, d_size);
707                         break;
708 #endif
709                 default:
710                         printf ("   No valid image found at 0x%08lx\n", img_addr);
711                         return ram_addr;
712                 }
713
714                 /* read in image data */
715                 debug ("   Reading image remaining data from dataflash address "
716                         "%08lx to RAM address %08lx\n", img_addr + h_size,
717                         ram_addr + h_size);
718
719                 read_dataflash (img_addr + h_size, d_size,
720                                 (char *)(ram_addr + h_size));
721
722         }
723 #endif /* CONFIG_HAS_DATAFLASH */
724
725         return ram_addr;
726 }
727
728 /**
729  * boot_get_ramdisk - main ramdisk handling routine
730  * @cmdtp: command table pointer
731  * @flag: command flag
732  * @argc: command argument count
733  * @argv: command argument list
734  * @images: pointer to the bootm images structure
735  * @arch: expected ramdisk architecture
736  * @rd_start: pointer to a ulong variable, will hold ramdisk start address
737  * @rd_end: pointer to a ulong variable, will hold ramdisk end
738  *
739  * boot_get_ramdisk() is responsible for finding a valid ramdisk image.
740  * Curently supported are the following ramdisk sources:
741  *      - multicomponent kernel/ramdisk image,
742  *      - commandline provided address of decicated ramdisk image.
743  *
744  * returns:
745  *     rd_start and rd_end are set to ramdisk start/end addresses if
746  *     ramdisk image is found and valid
747  *     rd_start and rd_end are set to 0 if no ramdisk exists
748  *     return 1 if ramdisk image is found but corrupted
749  */
750 int boot_get_ramdisk (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
751                 bootm_headers_t *images, uint8_t arch,
752                 ulong *rd_start, ulong *rd_end)
753 {
754         ulong rd_addr, rd_load;
755         ulong rd_data, rd_len;
756         image_header_t *rd_hdr;
757 #if defined(CONFIG_FIT)
758         void            *fit_hdr;
759         const char      *fit_uname_config = NULL;
760         const char      *fit_uname_ramdisk = NULL;
761         ulong           default_addr;
762 #endif
763
764         /*
765          * Look for a '-' which indicates to ignore the
766          * ramdisk argument
767          */
768         if ((argc >= 3) && (strcmp(argv[2], "-") ==  0)) {
769                 debug ("## Skipping init Ramdisk\n");
770                 rd_len = rd_data = 0;
771         } else if (argc >= 3) {
772 #if defined(CONFIG_FIT)
773                 /*
774                  * If the init ramdisk comes from the FIT image and the FIT image
775                  * address is omitted in the command line argument, try to use
776                  * os FIT image address or default load address.
777                  */
778                 if (images->fit_uname_os)
779                         default_addr = (ulong)images->fit_hdr_os;
780                 else
781                         default_addr = load_addr;
782
783                 if (fit_parse_conf (argv[2], default_addr,
784                                         &rd_addr, &fit_uname_config)) {
785                         debug ("*  ramdisk: config '%s' from image at 0x%08lx\n",
786                                         fit_uname_config, rd_addr);
787                 } else if (fit_parse_subimage (argv[2], default_addr,
788                                         &rd_addr, &fit_uname_ramdisk)) {
789                         debug ("*  ramdisk: subimage '%s' from image at 0x%08lx\n",
790                                         fit_uname_ramdisk, rd_addr);
791                 } else
792 #endif
793                 {
794                         rd_addr = simple_strtoul(argv[2], NULL, 16);
795                         debug ("*  ramdisk: cmdline image address = 0x%08lx\n",
796                                         rd_addr);
797                 }
798
799                 /* copy from dataflash if needed */
800                 printf ("## Loading init Ramdisk Image at %08lx ...\n",
801                                 rd_addr);
802                 rd_addr = genimg_get_image (rd_addr);
803
804                 /*
805                  * Check if there is an initrd image at the
806                  * address provided in the second bootm argument
807                  * check image type, for FIT images get FIT node.
808                  */
809                 switch (genimg_get_format ((void *)rd_addr)) {
810                 case IMAGE_FORMAT_LEGACY:
811
812                         debug ("*  ramdisk: legacy format image\n");
813
814                         rd_hdr = image_get_ramdisk (cmdtp, flag, argc, argv,
815                                                 rd_addr, arch, images->verify);
816
817                         if (rd_hdr == NULL) {
818                                 *rd_start = 0;
819                                 *rd_end = 0;
820                                 return 1;
821                         }
822
823                         rd_data = image_get_data (rd_hdr);
824                         rd_len = image_get_data_size (rd_hdr);
825                         rd_load = image_get_load (rd_hdr);
826                         break;
827 #if defined(CONFIG_FIT)
828                 case IMAGE_FORMAT_FIT:
829                         fit_hdr = (void *)rd_addr;
830                         debug ("*  ramdisk: FIT format image\n");
831                         fit_unsupported_reset ("ramdisk");
832                         return 1;
833 #endif
834                 default:
835                         printf ("Wrong Image Format for %s command\n",
836                                         cmdtp->name);
837                         rd_data = rd_len = 0;
838                 }
839
840 #if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
841                 /*
842                  * We need to copy the ramdisk to SRAM to let Linux boot
843                  */
844                 if (rd_data) {
845                         memmove ((void *)rd_load, (uchar *)rd_data, rd_len);
846                         rd_data = rd_load;
847                 }
848 #endif /* CONFIG_B2 || CONFIG_EVB4510 || CONFIG_ARMADILLO */
849
850         } else if (images->legacy_hdr_valid &&
851                         image_check_type (images->legacy_hdr_os, IH_TYPE_MULTI)) {
852                 /*
853                  * Now check if we have a legacy mult-component image,
854                  * get second entry data start address and len.
855                  */
856                 show_boot_progress (13);
857                 printf ("## Loading init Ramdisk from multi component "
858                                 "Image at %08lx ...\n",
859                                 (ulong)images->legacy_hdr_os);
860
861                 image_multi_getimg (images->legacy_hdr_os, 1, &rd_data, &rd_len);
862         } else {
863                 /*
864                  * no initrd image
865                  */
866                 show_boot_progress (14);
867                 rd_len = rd_data = 0;
868         }
869
870         if (!rd_data) {
871                 debug ("## No init Ramdisk\n");
872                 *rd_start = 0;
873                 *rd_end = 0;
874         } else {
875                 *rd_start = rd_data;
876                 *rd_end = rd_data + rd_len;
877         }
878         debug ("   ramdisk start = 0x%08lx, ramdisk end = 0x%08lx\n",
879                         *rd_start, *rd_end);
880
881         return 0;
882 }
883
884 #if defined(CONFIG_PPC) || defined(CONFIG_M68K)
885 /**
886  * boot_ramdisk_high - relocate init ramdisk
887  * @lmb: pointer to lmb handle, will be used for memory mgmt
888  * @rd_data: ramdisk data start address
889  * @rd_len: ramdisk data length
890  * @initrd_start: pointer to a ulong variable, will hold final init ramdisk
891  *      start address (after possible relocation)
892  * @initrd_end: pointer to a ulong variable, will hold final init ramdisk
893  *      end address (after possible relocation)
894  *
895  * boot_ramdisk_high() takes a relocation hint from "initrd_high" environement
896  * variable and if requested ramdisk data is moved to a specified location.
897  *
898  * Initrd_start and initrd_end are set to final (after relocation) ramdisk
899  * start/end addresses if ramdisk image start and len were provided,
900  * otherwise set initrd_start and initrd_end set to zeros.
901  *
902  * returns:
903  *      0 - success
904  *     -1 - failure
905  */
906 int boot_ramdisk_high (struct lmb *lmb, ulong rd_data, ulong rd_len,
907                   ulong *initrd_start, ulong *initrd_end)
908 {
909         char    *s;
910         ulong   initrd_high;
911         int     initrd_copy_to_ram = 1;
912
913         if ((s = getenv ("initrd_high")) != NULL) {
914                 /* a value of "no" or a similar string will act like 0,
915                  * turning the "load high" feature off. This is intentional.
916                  */
917                 initrd_high = simple_strtoul (s, NULL, 16);
918                 if (initrd_high == ~0)
919                         initrd_copy_to_ram = 0;
920         } else {
921                 /* not set, no restrictions to load high */
922                 initrd_high = ~0;
923         }
924
925         debug ("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
926                         initrd_high, initrd_copy_to_ram);
927
928         if (rd_data) {
929                 if (!initrd_copy_to_ram) {      /* zero-copy ramdisk support */
930                         debug ("   in-place initrd\n");
931                         *initrd_start = rd_data;
932                         *initrd_end = rd_data + rd_len;
933                         lmb_reserve(lmb, rd_data, rd_len);
934                 } else {
935                         if (initrd_high)
936                                 *initrd_start = lmb_alloc_base (lmb, rd_len, 0x1000, initrd_high);
937                         else
938                                 *initrd_start = lmb_alloc (lmb, rd_len, 0x1000);
939
940                         if (*initrd_start == 0) {
941                                 puts ("ramdisk - allocation error\n");
942                                 goto error;
943                         }
944                         show_boot_progress (12);
945
946                         *initrd_end = *initrd_start + rd_len;
947                         printf ("   Loading Ramdisk to %08lx, end %08lx ... ",
948                                         *initrd_start, *initrd_end);
949
950                         memmove_wd ((void *)*initrd_start,
951                                         (void *)rd_data, rd_len, CHUNKSZ);
952
953                         puts ("OK\n");
954                 }
955         } else {
956                 *initrd_start = 0;
957                 *initrd_end = 0;
958         }
959         debug ("   ramdisk load start = 0x%08lx, ramdisk load end = 0x%08lx\n",
960                         *initrd_start, *initrd_end);
961
962         return 0;
963
964 error:
965         return -1;
966 }
967
968 /**
969  * boot_get_cmdline - allocate and initialize kernel cmdline
970  * @lmb: pointer to lmb handle, will be used for memory mgmt
971  * @cmd_start: pointer to a ulong variable, will hold cmdline start
972  * @cmd_end: pointer to a ulong variable, will hold cmdline end
973  * @bootmap_base: ulong variable, holds offset in physical memory to
974  * base of bootmap
975  *
976  * boot_get_cmdline() allocates space for kernel command line below
977  * BOOTMAPSZ + bootmap_base address. If "bootargs" U-boot environemnt
978  * variable is present its contents is copied to allocated kernel
979  * command line.
980  *
981  * returns:
982  *      0 - success
983  *     -1 - failure
984  */
985 int boot_get_cmdline (struct lmb *lmb, ulong *cmd_start, ulong *cmd_end,
986                         ulong bootmap_base)
987 {
988         char *cmdline;
989         char *s;
990
991         cmdline = (char *)lmb_alloc_base(lmb, CFG_BARGSIZE, 0xf,
992                                          CFG_BOOTMAPSZ + bootmap_base);
993
994         if (cmdline == NULL)
995                 return -1;
996
997         if ((s = getenv("bootargs")) == NULL)
998                 s = "";
999
1000         strcpy(cmdline, s);
1001
1002         *cmd_start = (ulong) & cmdline[0];
1003         *cmd_end = *cmd_start + strlen(cmdline);
1004
1005         debug ("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end);
1006
1007         return 0;
1008 }
1009
1010 /**
1011  * boot_get_kbd - allocate and initialize kernel copy of board info
1012  * @lmb: pointer to lmb handle, will be used for memory mgmt
1013  * @kbd: double pointer to board info data
1014  * @bootmap_base: ulong variable, holds offset in physical memory to
1015  * base of bootmap
1016  *
1017  * boot_get_kbd() allocates space for kernel copy of board info data below
1018  * BOOTMAPSZ + bootmap_base address and kernel board info is initialized with
1019  * the current u-boot board info data.
1020  *
1021  * returns:
1022  *      0 - success
1023  *     -1 - failure
1024  */
1025 int boot_get_kbd (struct lmb *lmb, bd_t **kbd, ulong bootmap_base)
1026 {
1027         *kbd = (bd_t *)lmb_alloc_base(lmb, sizeof(bd_t), 0xf,
1028                                       CFG_BOOTMAPSZ + bootmap_base);
1029         if (*kbd == NULL)
1030                 return -1;
1031
1032         **kbd = *(gd->bd);
1033
1034         debug ("## kernel board info at 0x%08lx\n", (ulong)*kbd);
1035
1036 #if defined(DEBUG) && defined(CONFIG_CMD_BDI)
1037         do_bdinfo(NULL, 0, 0, NULL);
1038 #endif
1039
1040         return 0;
1041 }
1042 #endif /* CONFIG_PPC || CONFIG_M68K */
1043
1044 #if defined(CONFIG_FIT)
1045 /*****************************************************************************/
1046 /* New uImage format routines */
1047 /*****************************************************************************/
1048 static int fit_parse_spec (const char *spec, char sepc, ulong addr_curr,
1049                 ulong *addr, const char **name)
1050 {
1051         const char *sep;
1052
1053         *addr = addr_curr;
1054         *name = NULL;
1055
1056         sep = strchr (spec, sepc);
1057         if (sep) {
1058                 if (sep - spec > 0)
1059                         *addr = simple_strtoul (spec, NULL, 16);
1060
1061                 *name = sep + 1;
1062                 return 1;
1063         }
1064
1065         return 0;
1066 }
1067
1068 /**
1069  * fit_parse_conf - parse FIT configuration spec
1070  * @spec: input string, containing configuration spec
1071  * @add_curr: current image address (to be used as a possible default)
1072  * @addr: pointer to a ulong variable, will hold FIT image address of a given
1073  * configuration
1074  * @conf_name double pointer to a char, will hold pointer to a configuration
1075  * unit name
1076  *
1077  * fit_parse_conf() expects configuration spec in the for of [<addr>]#<conf>,
1078  * where <addr> is a FIT image address that contains configuration
1079  * with a <conf> unit name.
1080  *
1081  * Address part is optional, and if omitted default add_curr will
1082  * be used instead.
1083  *
1084  * returns:
1085  *     1 if spec is a valid configuration string,
1086  *     addr and conf_name are set accordingly
1087  *     0 otherwise
1088  */
1089 inline int fit_parse_conf (const char *spec, ulong addr_curr,
1090                 ulong *addr, const char **conf_name)
1091 {
1092         return fit_parse_spec (spec, '#', addr_curr, addr, conf_name);
1093 }
1094
1095 /**
1096  * fit_parse_subimage - parse FIT subimage spec
1097  * @spec: input string, containing subimage spec
1098  * @add_curr: current image address (to be used as a possible default)
1099  * @addr: pointer to a ulong variable, will hold FIT image address of a given
1100  * subimage
1101  * @image_name: double pointer to a char, will hold pointer to a subimage name
1102  *
1103  * fit_parse_subimage() expects subimage spec in the for of
1104  * [<addr>]:<subimage>, where <addr> is a FIT image address that contains
1105  * subimage with a <subimg> unit name.
1106  *
1107  * Address part is optional, and if omitted default add_curr will
1108  * be used instead.
1109  *
1110  * returns:
1111  *     1 if spec is a valid subimage string,
1112  *     addr and image_name are set accordingly
1113  *     0 otherwise
1114  */
1115 inline int fit_parse_subimage (const char *spec, ulong addr_curr,
1116                 ulong *addr, const char **image_name)
1117 {
1118         return fit_parse_spec (spec, ':', addr_curr, addr, image_name);
1119 }
1120
1121 #endif /* CONFIG_FIT */
1122 #endif /* !USE_HOSTCC */