blob: 202c8a1ca8fc4aaac093700ce8690d81f3708686 [file] [log] [blame]
Marian Balakowicz41d71ed2008-01-08 18:14:09 +01001/*
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 */
Marian Balakowicz9c701e82008-01-31 13:57:17 +010025
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010026#ifndef USE_HOSTCC
Marian Balakowicz95418502008-01-31 13:55:39 +010027#include <common.h>
28#include <watchdog.h>
29
30#ifdef CONFIG_SHOW_BOOT_PROGRESS
31#include <status_led.h>
32#endif
33
34#ifdef CONFIG_HAS_DATAFLASH
35#include <dataflash.h>
36#endif
37
Marian Balakowicz902ce702008-05-13 15:53:29 +020038#ifdef CONFIG_LOGBUFFER
39#include <logbuff.h>
40#endif
41
Marian Balakowicza1cc1472008-02-21 17:27:41 +010042#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE)
43#include <rtc.h>
44#endif
45
Marian Balakowicze227fbb2008-02-29 21:24:06 +010046#include <image.h>
47
Stephen Warren6904b6e2011-10-18 11:11:49 +000048#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
Marian Balakowiczc536d6f2008-02-21 17:20:19 +010049#include <fdt.h>
50#include <libfdt.h>
51#include <fdt_support.h>
Marian Balakowicza50d5152008-03-12 10:12:37 +010052#endif
53
54#if defined(CONFIG_FIT)
Andy Fleming72c23be2008-04-02 16:19:07 -050055#include <u-boot/md5.h>
Marian Balakowicze227fbb2008-02-29 21:24:06 +010056#include <sha1.h>
Marian Balakowicza50d5152008-03-12 10:12:37 +010057
Stephen Warren6904b6e2011-10-18 11:11:49 +000058static int fit_check_ramdisk(const void *fit, int os_noffset,
Marian Balakowicza50d5152008-03-12 10:12:37 +010059 uint8_t arch, int verify);
Marian Balakowiczc536d6f2008-02-21 17:20:19 +010060#endif
61
Marian Balakowicz2efc2642008-01-31 13:58:13 +010062#ifdef CONFIG_CMD_BDI
Wolfgang Denk6262d0212010-06-28 22:00:46 +020063extern int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
Marian Balakowicz2efc2642008-01-31 13:58:13 +010064#endif
65
66DECLARE_GLOBAL_DATA_PTR;
Marian Balakowicz61fde552008-02-27 11:01:04 +010067
Stephen Warren6904b6e2011-10-18 11:11:49 +000068static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
Marian Balakowicza0ffb422008-03-12 10:14:38 +010069 int verify);
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010070#else
Marian Balakowicz95418502008-01-31 13:55:39 +010071#include "mkimage.h"
Andy Fleming72c23be2008-04-02 16:19:07 -050072#include <u-boot/md5.h>
Marian Balakowicze227fbb2008-02-29 21:24:06 +010073#include <time.h>
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010074#include <image.h>
Marian Balakowicze227fbb2008-02-29 21:24:06 +010075#endif /* !USE_HOSTCC*/
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010076
Mike Frysingercf2feb12010-10-20 07:17:39 -040077static const table_entry_t uimage_arch[] = {
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +010078 { IH_ARCH_INVALID, NULL, "Invalid ARCH", },
79 { IH_ARCH_ALPHA, "alpha", "Alpha", },
80 { IH_ARCH_ARM, "arm", "ARM", },
81 { IH_ARCH_I386, "x86", "Intel x86", },
82 { IH_ARCH_IA64, "ia64", "IA64", },
83 { IH_ARCH_M68K, "m68k", "M68K", },
84 { IH_ARCH_MICROBLAZE, "microblaze", "MicroBlaze", },
85 { IH_ARCH_MIPS, "mips", "MIPS", },
86 { IH_ARCH_MIPS64, "mips64", "MIPS 64 Bit", },
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +010087 { IH_ARCH_NIOS2, "nios2", "NIOS II", },
Grant Erickson80f51b82008-05-04 16:45:01 -070088 { IH_ARCH_PPC, "powerpc", "PowerPC", },
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +010089 { IH_ARCH_PPC, "ppc", "PowerPC", },
90 { IH_ARCH_S390, "s390", "IBM S390", },
91 { IH_ARCH_SH, "sh", "SuperH", },
92 { IH_ARCH_SPARC, "sparc", "SPARC", },
93 { IH_ARCH_SPARC64, "sparc64", "SPARC 64 Bit", },
94 { IH_ARCH_BLACKFIN, "blackfin", "Blackfin", },
95 { IH_ARCH_AVR32, "avr32", "AVR32", },
Macpaul Lin354b4e32011-10-19 20:41:09 +000096 { IH_ARCH_NDS32, "nds32", "NDS32", },
Stefan Kristiansson15c669c2011-11-26 19:04:50 +000097 { IH_ARCH_OPENRISC, "or1k", "OpenRISC 1000",},
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +010098 { -1, "", "", },
99};
100
Mike Frysingercf2feb12010-10-20 07:17:39 -0400101static const table_entry_t uimage_os[] = {
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100102 { IH_OS_INVALID, NULL, "Invalid OS", },
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100103 { IH_OS_LINUX, "linux", "Linux", },
104#if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC)
105 { IH_OS_LYNXOS, "lynxos", "LynxOS", },
106#endif
107 { IH_OS_NETBSD, "netbsd", "NetBSD", },
Torkel Lundgren29a58662010-09-28 11:05:36 +0200108 { IH_OS_OSE, "ose", "Enea OSE", },
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100109 { IH_OS_RTEMS, "rtems", "RTEMS", },
110 { IH_OS_U_BOOT, "u-boot", "U-Boot", },
111#if defined(CONFIG_CMD_ELF) || defined(USE_HOSTCC)
112 { IH_OS_QNX, "qnx", "QNX", },
113 { IH_OS_VXWORKS, "vxworks", "VxWorks", },
114#endif
Peter Tyser56b8dd12008-09-08 14:56:49 -0500115#if defined(CONFIG_INTEGRITY) || defined(USE_HOSTCC)
116 { IH_OS_INTEGRITY,"integrity", "INTEGRITY", },
117#endif
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100118#ifdef USE_HOSTCC
119 { IH_OS_4_4BSD, "4_4bsd", "4_4BSD", },
120 { IH_OS_DELL, "dell", "Dell", },
121 { IH_OS_ESIX, "esix", "Esix", },
122 { IH_OS_FREEBSD, "freebsd", "FreeBSD", },
123 { IH_OS_IRIX, "irix", "Irix", },
124 { IH_OS_NCR, "ncr", "NCR", },
125 { IH_OS_OPENBSD, "openbsd", "OpenBSD", },
126 { IH_OS_PSOS, "psos", "pSOS", },
127 { IH_OS_SCO, "sco", "SCO", },
128 { IH_OS_SOLARIS, "solaris", "Solaris", },
129 { IH_OS_SVR4, "svr4", "SVR4", },
130#endif
131 { -1, "", "", },
132};
133
Mike Frysingercf2feb12010-10-20 07:17:39 -0400134static const table_entry_t uimage_type[] = {
Stefano Babic38855512011-10-17 00:07:43 +0000135 { IH_TYPE_AISIMAGE, "aisimage", "Davinci AIS image",},
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100136 { IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image", },
137 { IH_TYPE_FIRMWARE, "firmware", "Firmware", },
John Rigby34d12a12011-07-21 09:10:30 -0400138 { IH_TYPE_FLATDT, "flat_dt", "Flat Device Tree", },
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100139 { IH_TYPE_KERNEL, "kernel", "Kernel Image", },
Stephen Warren8c87eba2011-11-10 13:17:53 -0700140 { IH_TYPE_KERNEL_NOLOAD, "kernel_noload", "Kernel Image (no loading done)", },
Stefano Babic38855512011-10-17 00:07:43 +0000141 { IH_TYPE_KWBIMAGE, "kwbimage", "Kirkwood Boot Image",},
142 { IH_TYPE_IMXIMAGE, "imximage", "Freescale i.MX Boot Image",},
143 { IH_TYPE_INVALID, NULL, "Invalid Image", },
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100144 { IH_TYPE_MULTI, "multi", "Multi-File Image", },
Stefano Babic38855512011-10-17 00:07:43 +0000145 { IH_TYPE_OMAPIMAGE, "omapimage", "TI OMAP SPL With GP CH",},
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100146 { IH_TYPE_RAMDISK, "ramdisk", "RAMDisk Image", },
147 { IH_TYPE_SCRIPT, "script", "Script", },
148 { IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
Heiko Schocher58cb84d2011-07-16 00:06:42 +0000149 { IH_TYPE_UBLIMAGE, "ublimage", "Davinci UBL image",},
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100150 { -1, "", "", },
151};
152
Mike Frysingercf2feb12010-10-20 07:17:39 -0400153static const table_entry_t uimage_comp[] = {
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100154 { IH_COMP_NONE, "none", "uncompressed", },
155 { IH_COMP_BZIP2, "bzip2", "bzip2 compressed", },
156 { IH_COMP_GZIP, "gzip", "gzip compressed", },
Luigi 'Comio' Mantellini35afc062008-09-08 02:46:13 +0200157 { IH_COMP_LZMA, "lzma", "lzma compressed", },
Peter Korsgaardf7440cd2009-11-19 11:37:51 +0100158 { IH_COMP_LZO, "lzo", "lzo compressed", },
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100159 { -1, "", "", },
160};
161
Stephen Warren6904b6e2011-10-18 11:11:49 +0000162uint32_t crc32(uint32_t, const unsigned char *, uint);
163uint32_t crc32_wd(uint32_t, const unsigned char *, uint, uint);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100164#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
Stephen Warren6904b6e2011-10-18 11:11:49 +0000165static void genimg_print_time(time_t timestamp);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100166#endif
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100167
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100168/*****************************************************************************/
169/* Legacy format routines */
170/*****************************************************************************/
Stephen Warren6904b6e2011-10-18 11:11:49 +0000171int image_check_hcrc(const image_header_t *hdr)
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100172{
173 ulong hcrc;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000174 ulong len = image_get_header_size();
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100175 image_header_t header;
176
177 /* Copy header so we can blank CRC field for re-calculation */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000178 memmove(&header, (char *)hdr, image_get_header_size());
179 image_set_hcrc(&header, 0);
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100180
Stephen Warren6904b6e2011-10-18 11:11:49 +0000181 hcrc = crc32(0, (unsigned char *)&header, len);
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100182
Stephen Warren6904b6e2011-10-18 11:11:49 +0000183 return (hcrc == image_get_hcrc(hdr));
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100184}
185
Stephen Warren6904b6e2011-10-18 11:11:49 +0000186int image_check_dcrc(const image_header_t *hdr)
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100187{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000188 ulong data = image_get_data(hdr);
189 ulong len = image_get_data_size(hdr);
190 ulong dcrc = crc32_wd(0, (unsigned char *)data, len, CHUNKSZ_CRC32);
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100191
Stephen Warren6904b6e2011-10-18 11:11:49 +0000192 return (dcrc == image_get_dcrc(hdr));
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100193}
194
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100195/**
196 * image_multi_count - get component (sub-image) count
197 * @hdr: pointer to the header of the multi component image
198 *
199 * image_multi_count() returns number of components in a multi
200 * component image.
201 *
202 * Note: no checking of the image type is done, caller must pass
203 * a valid multi component image.
204 *
205 * returns:
206 * number of components
207 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000208ulong image_multi_count(const image_header_t *hdr)
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100209{
210 ulong i, count = 0;
Marian Balakowicza1474212008-02-29 16:00:06 +0100211 uint32_t *size;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100212
213 /* get start of the image payload, which in case of multi
214 * component images that points to a table of component sizes */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000215 size = (uint32_t *)image_get_data(hdr);
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100216
217 /* count non empty slots */
218 for (i = 0; size[i]; ++i)
219 count++;
220
221 return count;
222}
223
224/**
225 * image_multi_getimg - get component data address and size
226 * @hdr: pointer to the header of the multi component image
227 * @idx: index of the requested component
228 * @data: pointer to a ulong variable, will hold component data address
229 * @len: pointer to a ulong variable, will hold component size
230 *
231 * image_multi_getimg() returns size and data address for the requested
232 * component in a multi component image.
233 *
234 * Note: no checking of the image type is done, caller must pass
235 * a valid multi component image.
236 *
237 * returns:
238 * data address and size of the component, if idx is valid
239 * 0 in data and len, if idx is out of range
240 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000241void image_multi_getimg(const image_header_t *hdr, ulong idx,
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100242 ulong *data, ulong *len)
243{
244 int i;
Marian Balakowicza1474212008-02-29 16:00:06 +0100245 uint32_t *size;
Nick Spence143a1592008-05-10 14:02:04 -0700246 ulong offset, count, img_data;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100247
248 /* get number of component */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000249 count = image_multi_count(hdr);
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100250
251 /* get start of the image payload, which in case of multi
252 * component images that points to a table of component sizes */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000253 size = (uint32_t *)image_get_data(hdr);
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100254
255 /* get address of the proper component data start, which means
256 * skipping sizes table (add 1 for last, null entry) */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000257 img_data = image_get_data(hdr) + (count + 1) * sizeof(uint32_t);
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100258
259 if (idx < count) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000260 *len = uimage_to_cpu(size[idx]);
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100261 offset = 0;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100262
263 /* go over all indices preceding requested component idx */
264 for (i = 0; i < idx; i++) {
Nick Spence143a1592008-05-10 14:02:04 -0700265 /* add up i-th component size, rounding up to 4 bytes */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000266 offset += (uimage_to_cpu(size[i]) + 3) & ~3 ;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100267 }
268
269 /* calculate idx-th component data address */
Nick Spence143a1592008-05-10 14:02:04 -0700270 *data = img_data + offset;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +0100271 } else {
272 *len = 0;
273 *data = 0;
274 }
275}
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100276
Stephen Warren6904b6e2011-10-18 11:11:49 +0000277static void image_print_type(const image_header_t *hdr)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100278{
279 const char *os, *arch, *type, *comp;
280
Stephen Warren6904b6e2011-10-18 11:11:49 +0000281 os = genimg_get_os_name(image_get_os(hdr));
282 arch = genimg_get_arch_name(image_get_arch(hdr));
283 type = genimg_get_type_name(image_get_type(hdr));
284 comp = genimg_get_comp_name(image_get_comp(hdr));
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100285
Stephen Warren6904b6e2011-10-18 11:11:49 +0000286 printf("%s %s %s (%s)\n", arch, os, type, comp);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100287}
288
Marian Balakowicze227fbb2008-02-29 21:24:06 +0100289/**
Bartlomiej Sieka47868592008-04-18 12:39:23 +0200290 * image_print_contents - prints out the contents of the legacy format image
Wolfgang Denk3b506772009-08-19 11:42:56 +0200291 * @ptr: pointer to the legacy format image header
Marian Balakowicze227fbb2008-02-29 21:24:06 +0100292 * @p: pointer to prefix string
293 *
Bartlomiej Sieka47868592008-04-18 12:39:23 +0200294 * image_print_contents() formats a multi line legacy image contents description.
Marian Balakowicze227fbb2008-02-29 21:24:06 +0100295 * The routine prints out all header fields followed by the size/offset data
296 * for MULTI/SCRIPT images.
297 *
298 * returns:
299 * no returned results
300 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000301void image_print_contents(const void *ptr)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100302{
Wolfgang Denk3b506772009-08-19 11:42:56 +0200303 const image_header_t *hdr = (const image_header_t *)ptr;
Bartlomiej Sieka47868592008-04-18 12:39:23 +0200304 const char *p;
305
306#ifdef USE_HOSTCC
307 p = "";
308#else
309 p = " ";
310#endif
311
Stephen Warren6904b6e2011-10-18 11:11:49 +0000312 printf("%sImage Name: %.*s\n", p, IH_NMLEN, image_get_name(hdr));
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100313#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
Stephen Warren6904b6e2011-10-18 11:11:49 +0000314 printf("%sCreated: ", p);
315 genimg_print_time((time_t)image_get_time(hdr));
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100316#endif
Stephen Warren6904b6e2011-10-18 11:11:49 +0000317 printf("%sImage Type: ", p);
318 image_print_type(hdr);
319 printf("%sData Size: ", p);
320 genimg_print_size(image_get_data_size(hdr));
321 printf("%sLoad Address: %08x\n", p, image_get_load(hdr));
322 printf("%sEntry Point: %08x\n", p, image_get_ep(hdr));
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100323
Stephen Warren6904b6e2011-10-18 11:11:49 +0000324 if (image_check_type(hdr, IH_TYPE_MULTI) ||
325 image_check_type(hdr, IH_TYPE_SCRIPT)) {
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100326 int i;
327 ulong data, len;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000328 ulong count = image_multi_count(hdr);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100329
Stephen Warren6904b6e2011-10-18 11:11:49 +0000330 printf("%sContents:\n", p);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100331 for (i = 0; i < count; i++) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000332 image_multi_getimg(hdr, i, &data, &len);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100333
Stephen Warren6904b6e2011-10-18 11:11:49 +0000334 printf("%s Image %d: ", p, i);
335 genimg_print_size(len);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100336
Stephen Warren6904b6e2011-10-18 11:11:49 +0000337 if (image_check_type(hdr, IH_TYPE_SCRIPT) && i > 0) {
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100338 /*
339 * the user may need to know offsets
340 * if planning to do something with
341 * multiple files
342 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000343 printf("%s Offset = 0x%08lx\n", p, data);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100344 }
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100345 }
346 }
347}
348
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100349
350#ifndef USE_HOSTCC
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100351/**
352 * image_get_ramdisk - get and verify ramdisk image
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100353 * @rd_addr: ramdisk image start address
354 * @arch: expected ramdisk architecture
355 * @verify: checksum verification flag
356 *
357 * image_get_ramdisk() returns a pointer to the verified ramdisk image
358 * header. Routine receives image start address and expected architecture
359 * flag. Verification done covers data and header integrity and os/type/arch
360 * fields checking.
361 *
362 * If dataflash support is enabled routine checks for dataflash addresses
363 * and handles required dataflash reads.
364 *
365 * returns:
366 * pointer to a ramdisk image header, if image was found and valid
367 * otherwise, return NULL
368 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000369static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
Marian Balakowicza0ffb422008-03-12 10:14:38 +0100370 int verify)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100371{
Wolfgang Denk3b506772009-08-19 11:42:56 +0200372 const image_header_t *rd_hdr = (const image_header_t *)rd_addr;
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100373
Stephen Warren6904b6e2011-10-18 11:11:49 +0000374 if (!image_check_magic(rd_hdr)) {
375 puts("Bad Magic Number\n");
376 show_boot_progress(-10);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100377 return NULL;
378 }
379
Stephen Warren6904b6e2011-10-18 11:11:49 +0000380 if (!image_check_hcrc(rd_hdr)) {
381 puts("Bad Header Checksum\n");
382 show_boot_progress(-11);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100383 return NULL;
384 }
385
Stephen Warren6904b6e2011-10-18 11:11:49 +0000386 show_boot_progress(10);
387 image_print_contents(rd_hdr);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100388
389 if (verify) {
390 puts(" Verifying Checksum ... ");
Stephen Warren6904b6e2011-10-18 11:11:49 +0000391 if (!image_check_dcrc(rd_hdr)) {
392 puts("Bad Data CRC\n");
393 show_boot_progress(-12);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100394 return NULL;
395 }
396 puts("OK\n");
397 }
398
Stephen Warren6904b6e2011-10-18 11:11:49 +0000399 show_boot_progress(11);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100400
Stephen Warren6904b6e2011-10-18 11:11:49 +0000401 if (!image_check_os(rd_hdr, IH_OS_LINUX) ||
402 !image_check_arch(rd_hdr, arch) ||
403 !image_check_type(rd_hdr, IH_TYPE_RAMDISK)) {
404 printf("No Linux %s Ramdisk Image\n",
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100405 genimg_get_arch_name(arch));
Stephen Warren6904b6e2011-10-18 11:11:49 +0000406 show_boot_progress(-13);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100407 return NULL;
408 }
409
410 return rd_hdr;
411}
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100412#endif /* !USE_HOSTCC */
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100413
414/*****************************************************************************/
415/* Shared dual-format routines */
416/*****************************************************************************/
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100417#ifndef USE_HOSTCC
Stephen Warren6904b6e2011-10-18 11:11:49 +0000418int getenv_yesno(char *var)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100419{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000420 char *s = getenv(var);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100421 return (s && (*s == 'n')) ? 0 : 1;
422}
423
424ulong getenv_bootm_low(void)
425{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000426 char *s = getenv("bootm_low");
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100427 if (s) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000428 ulong tmp = simple_strtoul(s, NULL, 16);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100429 return tmp;
430 }
431
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200432#if defined(CONFIG_SYS_SDRAM_BASE)
433 return CONFIG_SYS_SDRAM_BASE;
Marian Balakowicz2499b042008-03-12 12:14:15 +0100434#elif defined(CONFIG_ARM)
435 return gd->bd->bi_dram[0].start;
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100436#else
437 return 0;
438#endif
439}
440
Becky Bruced26d67c2008-06-09 20:37:18 -0500441phys_size_t getenv_bootm_size(void)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100442{
Matthew McClintock6fc7d3a2010-07-08 10:11:08 -0500443 phys_size_t tmp;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000444 char *s = getenv("bootm_size");
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100445 if (s) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000446 tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100447 return tmp;
448 }
Matthew McClintock6fc7d3a2010-07-08 10:11:08 -0500449 s = getenv("bootm_low");
450 if (s)
Stephen Warren6904b6e2011-10-18 11:11:49 +0000451 tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
Matthew McClintock6fc7d3a2010-07-08 10:11:08 -0500452 else
453 tmp = 0;
454
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100455
Marian Balakowicz2499b042008-03-12 12:14:15 +0100456#if defined(CONFIG_ARM)
Matthew McClintock6fc7d3a2010-07-08 10:11:08 -0500457 return gd->bd->bi_dram[0].size - tmp;
Marian Balakowicz2499b042008-03-12 12:14:15 +0100458#else
Matthew McClintock6fc7d3a2010-07-08 10:11:08 -0500459 return gd->bd->bi_memsize - tmp;
Marian Balakowicz2499b042008-03-12 12:14:15 +0100460#endif
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100461}
462
Grant Likely26396382011-03-28 09:58:43 +0000463phys_size_t getenv_bootm_mapsize(void)
464{
465 phys_size_t tmp;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000466 char *s = getenv("bootm_mapsize");
Grant Likely26396382011-03-28 09:58:43 +0000467 if (s) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000468 tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
Grant Likely26396382011-03-28 09:58:43 +0000469 return tmp;
470 }
471
472#if defined(CONFIG_SYS_BOOTMAPSZ)
473 return CONFIG_SYS_BOOTMAPSZ;
474#else
475 return getenv_bootm_size();
476#endif
477}
478
Stephen Warren6904b6e2011-10-18 11:11:49 +0000479void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100480{
Larry Johnsone4551002010-04-20 08:09:43 -0400481 if (to == from)
482 return;
483
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100484#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
485 while (len > 0) {
486 size_t tail = (len > chunksz) ? chunksz : len;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000487 WATCHDOG_RESET();
488 memmove(to, from, tail);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100489 to += tail;
490 from += tail;
491 len -= tail;
492 }
493#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000494 memmove(to, from, len);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100495#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
496}
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100497#endif /* !USE_HOSTCC */
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100498
Stephen Warren6904b6e2011-10-18 11:11:49 +0000499void genimg_print_size(uint32_t size)
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100500{
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100501#ifndef USE_HOSTCC
Stephen Warren6904b6e2011-10-18 11:11:49 +0000502 printf("%d Bytes = ", size);
503 print_size(size, "\n");
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100504#else
Stephen Warren6904b6e2011-10-18 11:11:49 +0000505 printf("%d Bytes = %.2f kB = %.2f MB\n",
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100506 size, (double)size / 1.024e3,
507 (double)size / 1.048576e6);
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100508#endif
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100509}
510
511#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
Stephen Warren6904b6e2011-10-18 11:11:49 +0000512static void genimg_print_time(time_t timestamp)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100513{
514#ifndef USE_HOSTCC
515 struct rtc_time tm;
516
Stephen Warren6904b6e2011-10-18 11:11:49 +0000517 to_tm(timestamp, &tm);
518 printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n",
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100519 tm.tm_year, tm.tm_mon, tm.tm_mday,
520 tm.tm_hour, tm.tm_min, tm.tm_sec);
521#else
Stephen Warren6904b6e2011-10-18 11:11:49 +0000522 printf("%s", ctime(&timestamp));
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100523#endif
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100524}
525#endif /* CONFIG_TIMESTAMP || CONFIG_CMD_DATE || USE_HOSTCC */
526
527/**
528 * get_table_entry_name - translate entry id to long name
529 * @table: pointer to a translation table for entries of a specific type
530 * @msg: message to be returned when translation fails
531 * @id: entry id to be translated
532 *
533 * get_table_entry_name() will go over translation table trying to find
534 * entry that matches given id. If matching entry is found, its long
535 * name is returned to the caller.
536 *
537 * returns:
538 * long entry name if translation succeeds
539 * msg otherwise
540 */
Mike Frysingercf2feb12010-10-20 07:17:39 -0400541char *get_table_entry_name(const table_entry_t *table, char *msg, int id)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100542{
543 for (; table->id >= 0; ++table) {
544 if (table->id == id)
Wolfgang Denkd0813e52010-10-28 20:00:11 +0200545#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
Scott Wood68498ab2009-04-02 16:15:10 -0500546 return table->lname;
547#else
548 return table->lname + gd->reloc_off;
549#endif
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100550 }
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100551 return (msg);
552}
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100553
Stephen Warren6904b6e2011-10-18 11:11:49 +0000554const char *genimg_get_os_name(uint8_t os)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100555{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000556 return (get_table_entry_name(uimage_os, "Unknown OS", os));
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100557}
558
Stephen Warren6904b6e2011-10-18 11:11:49 +0000559const char *genimg_get_arch_name(uint8_t arch)
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100560{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000561 return (get_table_entry_name(uimage_arch, "Unknown Architecture",
562 arch));
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100563}
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100564
Stephen Warren6904b6e2011-10-18 11:11:49 +0000565const char *genimg_get_type_name(uint8_t type)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100566{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000567 return (get_table_entry_name(uimage_type, "Unknown Image", type));
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100568}
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100569
Stephen Warren6904b6e2011-10-18 11:11:49 +0000570const char *genimg_get_comp_name(uint8_t comp)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100571{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000572 return (get_table_entry_name(uimage_comp, "Unknown Compression",
573 comp));
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100574}
575
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100576/**
577 * get_table_entry_id - translate short entry name to id
578 * @table: pointer to a translation table for entries of a specific type
579 * @table_name: to be used in case of error
580 * @name: entry short name to be translated
581 *
582 * get_table_entry_id() will go over translation table trying to find
583 * entry that matches given short name. If matching entry is found,
584 * its id returned to the caller.
585 *
586 * returns:
587 * entry id if translation succeeds
588 * -1 otherwise
589 */
Mike Frysingercf2feb12010-10-20 07:17:39 -0400590int get_table_entry_id(const table_entry_t *table,
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100591 const char *table_name, const char *name)
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100592{
Mike Frysingercf2feb12010-10-20 07:17:39 -0400593 const table_entry_t *t;
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100594#ifdef USE_HOSTCC
595 int first = 1;
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100596
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100597 for (t = table; t->id >= 0; ++t) {
598 if (t->sname && strcasecmp(t->sname, name) == 0)
Stephen Warren6904b6e2011-10-18 11:11:49 +0000599 return(t->id);
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100600 }
601
Stephen Warren6904b6e2011-10-18 11:11:49 +0000602 fprintf(stderr, "\nInvalid %s Type - valid names are", table_name);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100603 for (t = table; t->id >= 0; ++t) {
604 if (t->sname == NULL)
605 continue;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000606 fprintf(stderr, "%c %s", (first) ? ':' : ',', t->sname);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100607 first = 0;
608 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000609 fprintf(stderr, "\n");
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100610#else
611 for (t = table; t->id >= 0; ++t) {
Wolfgang Denkd0813e52010-10-28 20:00:11 +0200612#ifdef CONFIG_NEEDS_MANUAL_RELOC
Scott Wood68498ab2009-04-02 16:15:10 -0500613 if (t->sname && strcmp(t->sname + gd->reloc_off, name) == 0)
Wolfgang Denkd0813e52010-10-28 20:00:11 +0200614#else
615 if (t->sname && strcmp(t->sname, name) == 0)
Peter Tyser9057cbf2009-09-21 11:20:36 -0500616#endif
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100617 return (t->id);
618 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000619 debug("Invalid %s Type: %s\n", table_name, name);
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100620#endif /* USE_HOSTCC */
621 return (-1);
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100622}
623
Stephen Warren6904b6e2011-10-18 11:11:49 +0000624int genimg_get_os_id(const char *name)
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100625{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000626 return (get_table_entry_id(uimage_os, "OS", name));
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100627}
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100628
Stephen Warren6904b6e2011-10-18 11:11:49 +0000629int genimg_get_arch_id(const char *name)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100630{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000631 return (get_table_entry_id(uimage_arch, "CPU", name));
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100632}
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100633
Stephen Warren6904b6e2011-10-18 11:11:49 +0000634int genimg_get_type_id(const char *name)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100635{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000636 return (get_table_entry_id(uimage_type, "Image", name));
Marian Balakowicz05c1d3f2008-01-31 13:20:07 +0100637}
Marian Balakowicz95418502008-01-31 13:55:39 +0100638
Stephen Warren6904b6e2011-10-18 11:11:49 +0000639int genimg_get_comp_id(const char *name)
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100640{
Stephen Warren6904b6e2011-10-18 11:11:49 +0000641 return (get_table_entry_id(uimage_comp, "Compression", name));
Marian Balakowiczc3c7eb22008-02-29 15:59:59 +0100642}
643
644#ifndef USE_HOSTCC
Marian Balakowicz95418502008-01-31 13:55:39 +0100645/**
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100646 * genimg_get_format - get image format type
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100647 * @img_addr: image start address
648 *
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100649 * genimg_get_format() checks whether provided address points to a valid
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100650 * legacy or FIT image.
651 *
Marian Balakowicz12560682008-02-27 11:02:26 +0100652 * New uImage format and FDT blob are based on a libfdt. FDT blob
653 * may be passed directly or embedded in a FIT image. In both situations
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100654 * genimg_get_format() must be able to dectect libfdt header.
Marian Balakowicz12560682008-02-27 11:02:26 +0100655 *
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100656 * returns:
657 * image format type or IMAGE_FORMAT_INVALID if no image is present
658 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000659int genimg_get_format(void *img_addr)
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100660{
Wolfgang Denk3b506772009-08-19 11:42:56 +0200661 ulong format = IMAGE_FORMAT_INVALID;
662 const image_header_t *hdr;
Marian Balakowicz12560682008-02-27 11:02:26 +0100663#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
Wolfgang Denk3b506772009-08-19 11:42:56 +0200664 char *fit_hdr;
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100665#endif
666
Wolfgang Denk3b506772009-08-19 11:42:56 +0200667 hdr = (const image_header_t *)img_addr;
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100668 if (image_check_magic(hdr))
669 format = IMAGE_FORMAT_LEGACY;
Marian Balakowicz12560682008-02-27 11:02:26 +0100670#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100671 else {
672 fit_hdr = (char *)img_addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000673 if (fdt_check_header(fit_hdr) == 0)
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100674 format = IMAGE_FORMAT_FIT;
675 }
676#endif
677
678 return format;
679}
680
681/**
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100682 * genimg_get_image - get image from special storage (if necessary)
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100683 * @img_addr: image start address
684 *
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100685 * genimg_get_image() checks if provided image start adddress is located
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100686 * in a dataflash storage. If so, image is moved to a system RAM memory.
687 *
688 * returns:
689 * image start address after possible relocation from special storage
690 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000691ulong genimg_get_image(ulong img_addr)
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100692{
Marian Balakowicz535b9102008-02-27 11:00:47 +0100693 ulong ram_addr = img_addr;
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100694
695#ifdef CONFIG_HAS_DATAFLASH
Marian Balakowicz535b9102008-02-27 11:00:47 +0100696 ulong h_size, d_size;
697
Stephen Warren6904b6e2011-10-18 11:11:49 +0000698 if (addr_dataflash(img_addr)) {
Marian Balakowicz535b9102008-02-27 11:00:47 +0100699 /* ger RAM address */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200700 ram_addr = CONFIG_SYS_LOAD_ADDR;
Marian Balakowicz535b9102008-02-27 11:00:47 +0100701
702 /* get header size */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000703 h_size = image_get_header_size();
Marian Balakowicz535b9102008-02-27 11:00:47 +0100704#if defined(CONFIG_FIT)
705 if (sizeof(struct fdt_header) > h_size)
706 h_size = sizeof(struct fdt_header);
707#endif
708
709 /* read in header */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000710 debug(" Reading image header from dataflash address "
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100711 "%08lx to RAM address %08lx\n", img_addr, ram_addr);
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100712
Stephen Warren6904b6e2011-10-18 11:11:49 +0000713 read_dataflash(img_addr, h_size, (char *)ram_addr);
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100714
Marian Balakowicz535b9102008-02-27 11:00:47 +0100715 /* get data size */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000716 switch (genimg_get_format((void *)ram_addr)) {
Marian Balakowicz535b9102008-02-27 11:00:47 +0100717 case IMAGE_FORMAT_LEGACY:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000718 d_size = image_get_data_size(
719 (const image_header_t *)ram_addr);
720 debug(" Legacy format image found at 0x%08lx, "
721 "size 0x%08lx\n",
Marian Balakowicz535b9102008-02-27 11:00:47 +0100722 ram_addr, d_size);
723 break;
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100724#if defined(CONFIG_FIT)
Marian Balakowicz535b9102008-02-27 11:00:47 +0100725 case IMAGE_FORMAT_FIT:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000726 d_size = fit_get_size((const void *)ram_addr) - h_size;
727 debug(" FIT/FDT format image found at 0x%08lx, "
728 "size 0x%08lx\n",
Marian Balakowicz535b9102008-02-27 11:00:47 +0100729 ram_addr, d_size);
730 break;
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100731#endif
Marian Balakowicz535b9102008-02-27 11:00:47 +0100732 default:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000733 printf(" No valid image found at 0x%08lx\n",
734 img_addr);
Marian Balakowicz535b9102008-02-27 11:00:47 +0100735 return ram_addr;
736 }
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100737
Marian Balakowicz535b9102008-02-27 11:00:47 +0100738 /* read in image data */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000739 debug(" Reading image remaining data from dataflash address "
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100740 "%08lx to RAM address %08lx\n", img_addr + h_size,
741 ram_addr + h_size);
742
Stephen Warren6904b6e2011-10-18 11:11:49 +0000743 read_dataflash(img_addr + h_size, d_size,
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100744 (char *)(ram_addr + h_size));
Marian Balakowicz535b9102008-02-27 11:00:47 +0100745
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100746 }
Marian Balakowicz535b9102008-02-27 11:00:47 +0100747#endif /* CONFIG_HAS_DATAFLASH */
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100748
749 return ram_addr;
750}
751
752/**
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100753 * fit_has_config - check if there is a valid FIT configuration
754 * @images: pointer to the bootm command headers structure
755 *
756 * fit_has_config() checks if there is a FIT configuration in use
757 * (if FTI support is present).
758 *
759 * returns:
760 * 0, no FIT support or no configuration found
761 * 1, configuration found
762 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000763int genimg_has_config(bootm_headers_t *images)
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100764{
765#if defined(CONFIG_FIT)
766 if (images->fit_uname_cfg)
767 return 1;
768#endif
769 return 0;
770}
771
772/**
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100773 * boot_get_ramdisk - main ramdisk handling routine
Marian Balakowicz95418502008-01-31 13:55:39 +0100774 * @argc: command argument count
775 * @argv: command argument list
Marian Balakowicz61fde552008-02-27 11:01:04 +0100776 * @images: pointer to the bootm images structure
Marian Balakowicz95418502008-01-31 13:55:39 +0100777 * @arch: expected ramdisk architecture
778 * @rd_start: pointer to a ulong variable, will hold ramdisk start address
779 * @rd_end: pointer to a ulong variable, will hold ramdisk end
780 *
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100781 * boot_get_ramdisk() is responsible for finding a valid ramdisk image.
Marian Balakowicz95418502008-01-31 13:55:39 +0100782 * Curently supported are the following ramdisk sources:
783 * - multicomponent kernel/ramdisk image,
784 * - commandline provided address of decicated ramdisk image.
785 *
786 * returns:
Marian Balakowicza0ffb422008-03-12 10:14:38 +0100787 * 0, if ramdisk image was found and valid, or skiped
Marian Balakowicz95418502008-01-31 13:55:39 +0100788 * rd_start and rd_end are set to ramdisk start/end addresses if
789 * ramdisk image is found and valid
Marian Balakowicza0ffb422008-03-12 10:14:38 +0100790 *
Kumar Galab8ca7342008-08-29 19:08:29 -0500791 * 1, if ramdisk image is found but corrupted, or invalid
Marian Balakowicz95418502008-01-31 13:55:39 +0100792 * rd_start and rd_end are set to 0 if no ramdisk exists
Marian Balakowicz95418502008-01-31 13:55:39 +0100793 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000794int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
Marian Balakowicza0ffb422008-03-12 10:14:38 +0100795 uint8_t arch, ulong *rd_start, ulong *rd_end)
Marian Balakowicz95418502008-01-31 13:55:39 +0100796{
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100797 ulong rd_addr, rd_load;
Marian Balakowicz95418502008-01-31 13:55:39 +0100798 ulong rd_data, rd_len;
Wolfgang Denk3b506772009-08-19 11:42:56 +0200799 const image_header_t *rd_hdr;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100800#if defined(CONFIG_FIT)
801 void *fit_hdr;
802 const char *fit_uname_config = NULL;
803 const char *fit_uname_ramdisk = NULL;
804 ulong default_addr;
Marian Balakowicza50d5152008-03-12 10:12:37 +0100805 int rd_noffset;
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100806 int cfg_noffset;
Marian Balakowicza50d5152008-03-12 10:12:37 +0100807 const void *data;
808 size_t size;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100809#endif
Marian Balakowicz95418502008-01-31 13:55:39 +0100810
Marian Balakowicza50d5152008-03-12 10:12:37 +0100811 *rd_start = 0;
812 *rd_end = 0;
813
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100814 /*
815 * Look for a '-' which indicates to ignore the
816 * ramdisk argument
817 */
818 if ((argc >= 3) && (strcmp(argv[2], "-") == 0)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000819 debug("## Skipping init Ramdisk\n");
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100820 rd_len = rd_data = 0;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000821 } else if (argc >= 3 || genimg_has_config(images)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100822#if defined(CONFIG_FIT)
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100823 if (argc >= 3) {
824 /*
825 * If the init ramdisk comes from the FIT image and
826 * the FIT image address is omitted in the command
827 * line argument, try to use os FIT image address or
828 * default load address.
829 */
830 if (images->fit_uname_os)
831 default_addr = (ulong)images->fit_hdr_os;
832 else
833 default_addr = load_addr;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100834
Stephen Warren6904b6e2011-10-18 11:11:49 +0000835 if (fit_parse_conf(argv[2], default_addr,
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100836 &rd_addr, &fit_uname_config)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000837 debug("* ramdisk: config '%s' from image at "
838 "0x%08lx\n",
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100839 fit_uname_config, rd_addr);
Stephen Warren6904b6e2011-10-18 11:11:49 +0000840 } else if (fit_parse_subimage(argv[2], default_addr,
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100841 &rd_addr, &fit_uname_ramdisk)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000842 debug("* ramdisk: subimage '%s' from image at "
843 "0x%08lx\n",
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100844 fit_uname_ramdisk, rd_addr);
845 } else
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100846#endif
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100847 {
848 rd_addr = simple_strtoul(argv[2], NULL, 16);
Stephen Warren6904b6e2011-10-18 11:11:49 +0000849 debug("* ramdisk: cmdline image address = "
850 "0x%08lx\n",
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100851 rd_addr);
852 }
853#if defined(CONFIG_FIT)
854 } else {
855 /* use FIT configuration provided in first bootm
856 * command argument
857 */
858 rd_addr = (ulong)images->fit_hdr_os;
859 fit_uname_config = images->fit_uname_cfg;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000860 debug("* ramdisk: using config '%s' from image "
861 "at 0x%08lx\n",
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100862 fit_uname_config, rd_addr);
863
864 /*
865 * Check whether configuration has ramdisk defined,
866 * if not, don't try to use it, quit silently.
867 */
868 fit_hdr = (void *)rd_addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000869 cfg_noffset = fit_conf_get_node(fit_hdr,
870 fit_uname_config);
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100871 if (cfg_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000872 debug("* ramdisk: no such config\n");
Michal Simekb2474002008-07-11 10:43:13 +0200873 return 1;
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100874 }
875
Stephen Warren6904b6e2011-10-18 11:11:49 +0000876 rd_noffset = fit_conf_get_ramdisk_node(fit_hdr,
877 cfg_noffset);
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100878 if (rd_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000879 debug("* ramdisk: no ramdisk in config\n");
Peter Tyser190ee482008-08-05 10:51:57 -0500880 return 0;
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100881 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100882 }
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100883#endif
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100884
885 /* copy from dataflash if needed */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000886 rd_addr = genimg_get_image(rd_addr);
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100887
888 /*
889 * Check if there is an initrd image at the
890 * address provided in the second bootm argument
891 * check image type, for FIT images get FIT node.
892 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000893 switch (genimg_get_format((void *)rd_addr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100894 case IMAGE_FORMAT_LEGACY:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000895 printf("## Loading init Ramdisk from Legacy "
Marian Balakowicza50d5152008-03-12 10:12:37 +0100896 "Image at %08lx ...\n", rd_addr);
Marian Balakowicz95418502008-01-31 13:55:39 +0100897
Stephen Warren6904b6e2011-10-18 11:11:49 +0000898 show_boot_progress(9);
899 rd_hdr = image_get_ramdisk(rd_addr, arch,
Marian Balakowicza0ffb422008-03-12 10:14:38 +0100900 images->verify);
Marian Balakowicz95418502008-01-31 13:55:39 +0100901
Marian Balakowicza50d5152008-03-12 10:12:37 +0100902 if (rd_hdr == NULL)
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600903 return 1;
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600904
Stephen Warren6904b6e2011-10-18 11:11:49 +0000905 rd_data = image_get_data(rd_hdr);
906 rd_len = image_get_data_size(rd_hdr);
907 rd_load = image_get_load(rd_hdr);
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100908 break;
909#if defined(CONFIG_FIT)
910 case IMAGE_FORMAT_FIT:
911 fit_hdr = (void *)rd_addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +0000912 printf("## Loading init Ramdisk from FIT "
Marian Balakowicza50d5152008-03-12 10:12:37 +0100913 "Image at %08lx ...\n", rd_addr);
914
Stephen Warren6904b6e2011-10-18 11:11:49 +0000915 show_boot_progress(120);
916 if (!fit_check_format(fit_hdr)) {
917 puts("Bad FIT ramdisk image format!\n");
918 show_boot_progress(-120);
Michal Simekb2474002008-07-11 10:43:13 +0200919 return 1;
Marian Balakowicza50d5152008-03-12 10:12:37 +0100920 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000921 show_boot_progress(121);
Marian Balakowicza50d5152008-03-12 10:12:37 +0100922
923 if (!fit_uname_ramdisk) {
924 /*
925 * no ramdisk image node unit name, try to get config
926 * node first. If config unit node name is NULL
927 * fit_conf_get_node() will try to find default config node
928 */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000929 show_boot_progress(122);
930 cfg_noffset = fit_conf_get_node(fit_hdr,
931 fit_uname_config);
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100932 if (cfg_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000933 puts("Could not find configuration "
934 "node\n");
935 show_boot_progress(-122);
Michal Simekb2474002008-07-11 10:43:13 +0200936 return 1;
Marian Balakowicz74eb4ae2008-03-12 10:33:01 +0100937 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000938 fit_uname_config = fdt_get_name(fit_hdr,
939 cfg_noffset, NULL);
940 printf(" Using '%s' configuration\n",
941 fit_uname_config);
Marian Balakowicza50d5152008-03-12 10:12:37 +0100942
Stephen Warren6904b6e2011-10-18 11:11:49 +0000943 rd_noffset = fit_conf_get_ramdisk_node(fit_hdr,
944 cfg_noffset);
945 fit_uname_ramdisk = fit_get_name(fit_hdr,
946 rd_noffset, NULL);
Marian Balakowicza50d5152008-03-12 10:12:37 +0100947 } else {
948 /* get ramdisk component image node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000949 show_boot_progress(123);
950 rd_noffset = fit_image_get_node(fit_hdr,
951 fit_uname_ramdisk);
Marian Balakowicza50d5152008-03-12 10:12:37 +0100952 }
Marian Balakowicz74eb4ae2008-03-12 10:33:01 +0100953 if (rd_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +0000954 puts("Could not find subimage node\n");
955 show_boot_progress(-124);
Michal Simekb2474002008-07-11 10:43:13 +0200956 return 1;
Marian Balakowicz74eb4ae2008-03-12 10:33:01 +0100957 }
Marian Balakowicza50d5152008-03-12 10:12:37 +0100958
Stephen Warren6904b6e2011-10-18 11:11:49 +0000959 printf(" Trying '%s' ramdisk subimage\n",
960 fit_uname_ramdisk);
Marian Balakowicza50d5152008-03-12 10:12:37 +0100961
Stephen Warren6904b6e2011-10-18 11:11:49 +0000962 show_boot_progress(125);
963 if (!fit_check_ramdisk(fit_hdr, rd_noffset, arch,
964 images->verify))
Michal Simekb2474002008-07-11 10:43:13 +0200965 return 1;
Marian Balakowicza50d5152008-03-12 10:12:37 +0100966
967 /* get ramdisk image data address and length */
Stephen Warren6904b6e2011-10-18 11:11:49 +0000968 if (fit_image_get_data(fit_hdr, rd_noffset, &data,
969 &size)) {
970 puts("Could not find ramdisk subimage data!\n");
971 show_boot_progress(-127);
Michal Simekb2474002008-07-11 10:43:13 +0200972 return 1;
Marian Balakowicza50d5152008-03-12 10:12:37 +0100973 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000974 show_boot_progress(128);
Marian Balakowicza50d5152008-03-12 10:12:37 +0100975
976 rd_data = (ulong)data;
977 rd_len = size;
978
Stephen Warren6904b6e2011-10-18 11:11:49 +0000979 if (fit_image_get_load(fit_hdr, rd_noffset, &rd_load)) {
980 puts("Can't get ramdisk subimage load "
981 "address!\n");
982 show_boot_progress(-129);
Michal Simekb2474002008-07-11 10:43:13 +0200983 return 1;
Marian Balakowicza50d5152008-03-12 10:12:37 +0100984 }
Stephen Warren6904b6e2011-10-18 11:11:49 +0000985 show_boot_progress(129);
Marian Balakowicza50d5152008-03-12 10:12:37 +0100986
987 images->fit_hdr_rd = fit_hdr;
988 images->fit_uname_rd = fit_uname_ramdisk;
Marian Balakowicz61c1ad52008-03-12 10:32:59 +0100989 images->fit_noffset_rd = rd_noffset;
Marian Balakowicza50d5152008-03-12 10:12:37 +0100990 break;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100991#endif
992 default:
Stephen Warren6904b6e2011-10-18 11:11:49 +0000993 puts("Wrong Ramdisk Image Format\n");
Marian Balakowicza50d5152008-03-12 10:12:37 +0100994 rd_data = rd_len = rd_load = 0;
Kumar Galab8ca7342008-08-29 19:08:29 -0500995 return 1;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100996 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100997 } else if (images->legacy_hdr_valid &&
Stephen Warren6904b6e2011-10-18 11:11:49 +0000998 image_check_type(&images->legacy_hdr_os_copy,
999 IH_TYPE_MULTI)) {
1000
Marian Balakowicz95418502008-01-31 13:55:39 +01001001 /*
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +01001002 * Now check if we have a legacy mult-component image,
1003 * get second entry data start address and len.
Marian Balakowicz95418502008-01-31 13:55:39 +01001004 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001005 show_boot_progress(13);
1006 printf("## Loading init Ramdisk from multi component "
Marian Balakowicza50d5152008-03-12 10:12:37 +01001007 "Legacy Image at %08lx ...\n",
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +01001008 (ulong)images->legacy_hdr_os);
1009
Stephen Warren6904b6e2011-10-18 11:11:49 +00001010 image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
Marian Balakowicz95418502008-01-31 13:55:39 +01001011 } else {
1012 /*
1013 * no initrd image
1014 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001015 show_boot_progress(14);
Marian Balakowicz95418502008-01-31 13:55:39 +01001016 rd_len = rd_data = 0;
1017 }
1018
1019 if (!rd_data) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001020 debug("## No init Ramdisk\n");
Marian Balakowicz95418502008-01-31 13:55:39 +01001021 } else {
1022 *rd_start = rd_data;
1023 *rd_end = rd_data + rd_len;
1024 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001025 debug(" ramdisk start = 0x%08lx, ramdisk end = 0x%08lx\n",
Marian Balakowicz95418502008-01-31 13:55:39 +01001026 *rd_start, *rd_end);
Kumar Gala18f4c0f2008-02-27 21:51:46 -06001027
1028 return 0;
Marian Balakowicz95418502008-01-31 13:55:39 +01001029}
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001030
John Rigbyeea8e692010-10-13 13:57:35 -06001031#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001032/**
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001033 * boot_ramdisk_high - relocate init ramdisk
Kumar Galab937bb72008-02-27 21:51:49 -06001034 * @lmb: pointer to lmb handle, will be used for memory mgmt
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001035 * @rd_data: ramdisk data start address
1036 * @rd_len: ramdisk data length
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001037 * @initrd_start: pointer to a ulong variable, will hold final init ramdisk
1038 * start address (after possible relocation)
1039 * @initrd_end: pointer to a ulong variable, will hold final init ramdisk
1040 * end address (after possible relocation)
1041 *
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001042 * boot_ramdisk_high() takes a relocation hint from "initrd_high" environement
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001043 * variable and if requested ramdisk data is moved to a specified location.
1044 *
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001045 * Initrd_start and initrd_end are set to final (after relocation) ramdisk
1046 * start/end addresses if ramdisk image start and len were provided,
1047 * otherwise set initrd_start and initrd_end set to zeros.
1048 *
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001049 * returns:
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001050 * 0 - success
1051 * -1 - failure
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001052 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001053int boot_ramdisk_high(struct lmb *lmb, ulong rd_data, ulong rd_len,
Kumar Galab937bb72008-02-27 21:51:49 -06001054 ulong *initrd_start, ulong *initrd_end)
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001055{
1056 char *s;
1057 ulong initrd_high;
1058 int initrd_copy_to_ram = 1;
1059
Stephen Warren6904b6e2011-10-18 11:11:49 +00001060 if ((s = getenv("initrd_high")) != NULL) {
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001061 /* a value of "no" or a similar string will act like 0,
1062 * turning the "load high" feature off. This is intentional.
1063 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001064 initrd_high = simple_strtoul(s, NULL, 16);
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001065 if (initrd_high == ~0)
1066 initrd_copy_to_ram = 0;
1067 } else {
1068 /* not set, no restrictions to load high */
1069 initrd_high = ~0;
1070 }
1071
Marian Balakowicz902ce702008-05-13 15:53:29 +02001072
1073#ifdef CONFIG_LOGBUFFER
1074 /* Prevent initrd from overwriting logbuffer */
1075 lmb_reserve(lmb, logbuffer_base() - LOGBUFF_OVERHEAD, LOGBUFF_RESERVE);
1076#endif
1077
Stephen Warren6904b6e2011-10-18 11:11:49 +00001078 debug("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001079 initrd_high, initrd_copy_to_ram);
1080
1081 if (rd_data) {
1082 if (!initrd_copy_to_ram) { /* zero-copy ramdisk support */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001083 debug(" in-place initrd\n");
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001084 *initrd_start = rd_data;
1085 *initrd_end = rd_data + rd_len;
Kumar Galab937bb72008-02-27 21:51:49 -06001086 lmb_reserve(lmb, rd_data, rd_len);
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001087 } else {
Kumar Galab937bb72008-02-27 21:51:49 -06001088 if (initrd_high)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001089 *initrd_start = (ulong)lmb_alloc_base(lmb,
1090 rd_len, 0x1000, initrd_high);
Kumar Galab937bb72008-02-27 21:51:49 -06001091 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00001092 *initrd_start = (ulong)lmb_alloc(lmb, rd_len,
1093 0x1000);
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001094
Kumar Galab937bb72008-02-27 21:51:49 -06001095 if (*initrd_start == 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001096 puts("ramdisk - allocation error\n");
Kumar Galab937bb72008-02-27 21:51:49 -06001097 goto error;
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001098 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001099 show_boot_progress(12);
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001100
1101 *initrd_end = *initrd_start + rd_len;
Stephen Warren6904b6e2011-10-18 11:11:49 +00001102 printf(" Loading Ramdisk to %08lx, end %08lx ... ",
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001103 *initrd_start, *initrd_end);
1104
Stephen Warren6904b6e2011-10-18 11:11:49 +00001105 memmove_wd((void *)*initrd_start,
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001106 (void *)rd_data, rd_len, CHUNKSZ);
1107
Kumar Gala180c5812011-12-07 04:42:58 +00001108#ifdef CONFIG_MP
1109 /*
1110 * Ensure the image is flushed to memory to handle
1111 * AMP boot scenarios in which we might not be
1112 * HW cache coherent
1113 */
1114 flush_cache((unsigned long)*initrd_start, rd_len);
1115#endif
Stephen Warren6904b6e2011-10-18 11:11:49 +00001116 puts("OK\n");
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001117 }
1118 } else {
1119 *initrd_start = 0;
1120 *initrd_end = 0;
1121 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001122 debug(" ramdisk load start = 0x%08lx, ramdisk load end = 0x%08lx\n",
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001123 *initrd_start, *initrd_end);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001124
Kumar Galab937bb72008-02-27 21:51:49 -06001125 return 0;
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001126
Kumar Galab937bb72008-02-27 21:51:49 -06001127error:
1128 return -1;
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001129}
John Rigbyeea8e692010-10-13 13:57:35 -06001130#endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001131
Kumar Galaa5130ad2008-08-15 08:24:38 -05001132#ifdef CONFIG_OF_LIBFDT
Stephen Warren6904b6e2011-10-18 11:11:49 +00001133static void fdt_error(const char *msg)
Kumar Galaa5130ad2008-08-15 08:24:38 -05001134{
Stephen Warren6904b6e2011-10-18 11:11:49 +00001135 puts("ERROR: ");
1136 puts(msg);
1137 puts(" - must RESET the board to recover.\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001138}
1139
Stephen Warren6904b6e2011-10-18 11:11:49 +00001140static const image_header_t *image_get_fdt(ulong fdt_addr)
Kumar Galaa5130ad2008-08-15 08:24:38 -05001141{
Wolfgang Denk3b506772009-08-19 11:42:56 +02001142 const image_header_t *fdt_hdr = (const image_header_t *)fdt_addr;
Kumar Galaa5130ad2008-08-15 08:24:38 -05001143
Stephen Warren6904b6e2011-10-18 11:11:49 +00001144 image_print_contents(fdt_hdr);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001145
Stephen Warren6904b6e2011-10-18 11:11:49 +00001146 puts(" Verifying Checksum ... ");
1147 if (!image_check_hcrc(fdt_hdr)) {
1148 fdt_error("fdt header checksum invalid");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001149 return NULL;
1150 }
1151
Stephen Warren6904b6e2011-10-18 11:11:49 +00001152 if (!image_check_dcrc(fdt_hdr)) {
1153 fdt_error("fdt checksum invalid");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001154 return NULL;
1155 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001156 puts("OK\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001157
Stephen Warren6904b6e2011-10-18 11:11:49 +00001158 if (!image_check_type(fdt_hdr, IH_TYPE_FLATDT)) {
1159 fdt_error("uImage is not a fdt");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001160 return NULL;
1161 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001162 if (image_get_comp(fdt_hdr) != IH_COMP_NONE) {
1163 fdt_error("uImage is compressed");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001164 return NULL;
1165 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001166 if (fdt_check_header((char *)image_get_data(fdt_hdr)) != 0) {
1167 fdt_error("uImage data is not a fdt");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001168 return NULL;
1169 }
1170 return fdt_hdr;
1171}
1172
1173/**
1174 * fit_check_fdt - verify FIT format FDT subimage
1175 * @fit_hdr: pointer to the FIT header
1176 * fdt_noffset: FDT subimage node offset within FIT image
1177 * @verify: data CRC verification flag
1178 *
1179 * fit_check_fdt() verifies integrity of the FDT subimage and from
1180 * specified FIT image.
1181 *
1182 * returns:
1183 * 1, on success
1184 * 0, on failure
1185 */
1186#if defined(CONFIG_FIT)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001187static int fit_check_fdt(const void *fit, int fdt_noffset, int verify)
Kumar Galaa5130ad2008-08-15 08:24:38 -05001188{
Stephen Warren6904b6e2011-10-18 11:11:49 +00001189 fit_image_print(fit, fdt_noffset, " ");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001190
1191 if (verify) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001192 puts(" Verifying Hash Integrity ... ");
1193 if (!fit_image_check_hashes(fit, fdt_noffset)) {
1194 fdt_error("Bad Data Hash");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001195 return 0;
1196 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001197 puts("OK\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001198 }
1199
Stephen Warren6904b6e2011-10-18 11:11:49 +00001200 if (!fit_image_check_type(fit, fdt_noffset, IH_TYPE_FLATDT)) {
1201 fdt_error("Not a FDT image");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001202 return 0;
1203 }
1204
Stephen Warren6904b6e2011-10-18 11:11:49 +00001205 if (!fit_image_check_comp(fit, fdt_noffset, IH_COMP_NONE)) {
1206 fdt_error("FDT image is compressed");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001207 return 0;
1208 }
1209
1210 return 1;
1211}
1212#endif /* CONFIG_FIT */
1213
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001214#ifndef CONFIG_SYS_FDT_PAD
1215#define CONFIG_SYS_FDT_PAD 0x3000
Kumar Galaa5130ad2008-08-15 08:24:38 -05001216#endif
1217
Grant Likely20f54922011-03-28 09:59:01 +00001218#if defined(CONFIG_OF_LIBFDT)
1219/**
1220 * boot_fdt_add_mem_rsv_regions - Mark the memreserve sections as unusable
1221 * @lmb: pointer to lmb handle, will be used for memory mgmt
1222 * @fdt_blob: pointer to fdt blob base address
1223 *
1224 * Adds the memreserve regions in the dtb to the lmb block. Adding the
1225 * memreserve regions prevents u-boot from using them to store the initrd
1226 * or the fdt blob.
1227 */
1228void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob)
1229{
1230 uint64_t addr, size;
1231 int i, total;
1232
Stephen Warren6904b6e2011-10-18 11:11:49 +00001233 if (fdt_check_header(fdt_blob) != 0)
Grant Likely20f54922011-03-28 09:59:01 +00001234 return;
1235
1236 total = fdt_num_mem_rsv(fdt_blob);
1237 for (i = 0; i < total; i++) {
1238 if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0)
1239 continue;
1240 printf(" reserving fdt memory region: addr=%llx size=%llx\n",
1241 (unsigned long long)addr, (unsigned long long)size);
1242 lmb_reserve(lmb, addr, size);
1243 }
1244}
1245
Kumar Galaa5130ad2008-08-15 08:24:38 -05001246/**
1247 * boot_relocate_fdt - relocate flat device tree
1248 * @lmb: pointer to lmb handle, will be used for memory mgmt
Kumar Galaa5130ad2008-08-15 08:24:38 -05001249 * @of_flat_tree: pointer to a char* variable, will hold fdt start address
1250 * @of_size: pointer to a ulong variable, will hold fdt length
1251 *
Timur Tabi6b8f2f82010-05-24 15:10:25 -05001252 * boot_relocate_fdt() allocates a region of memory within the bootmap and
1253 * relocates the of_flat_tree into that region, even if the fdt is already in
1254 * the bootmap. It also expands the size of the fdt by CONFIG_SYS_FDT_PAD
1255 * bytes.
Kumar Galaa5130ad2008-08-15 08:24:38 -05001256 *
1257 * of_flat_tree and of_size are set to final (after relocation) values
1258 *
1259 * returns:
1260 * 0 - success
1261 * 1 - failure
1262 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001263int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
Kumar Galaa5130ad2008-08-15 08:24:38 -05001264{
Timur Tabi6b8f2f82010-05-24 15:10:25 -05001265 void *fdt_blob = *of_flat_tree;
1266 void *of_start = 0;
David A. Longd558a4e2011-07-09 16:40:19 -04001267 char *fdt_high;
Kumar Galaa5130ad2008-08-15 08:24:38 -05001268 ulong of_len = 0;
Timur Tabi6b8f2f82010-05-24 15:10:25 -05001269 int err;
David A. Longd558a4e2011-07-09 16:40:19 -04001270 int disable_relocation = 0;
Kumar Galaa5130ad2008-08-15 08:24:38 -05001271
1272 /* nothing to do */
1273 if (*of_size == 0)
1274 return 0;
1275
Stephen Warren6904b6e2011-10-18 11:11:49 +00001276 if (fdt_check_header(fdt_blob) != 0) {
1277 fdt_error("image is not a fdt");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001278 goto error;
1279 }
1280
Timur Tabi6b8f2f82010-05-24 15:10:25 -05001281 /* position on a 4K boundary before the alloc_current */
1282 /* Pad the FDT by a specified amount */
1283 of_len = *of_size + CONFIG_SYS_FDT_PAD;
David A. Longd558a4e2011-07-09 16:40:19 -04001284
1285 /* If fdt_high is set use it to select the relocation address */
1286 fdt_high = getenv("fdt_high");
1287 if (fdt_high) {
1288 void *desired_addr = (void *)simple_strtoul(fdt_high, NULL, 16);
1289
1290 if (((ulong) desired_addr) == ~0UL) {
1291 /* All ones means use fdt in place */
1292 desired_addr = fdt_blob;
1293 disable_relocation = 1;
1294 }
1295 if (desired_addr) {
1296 of_start =
1297 (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
1298 ((ulong)
1299 desired_addr)
1300 + of_len);
1301 if (desired_addr && of_start != desired_addr) {
1302 puts("Failed using fdt_high value for Device Tree");
1303 goto error;
1304 }
1305 } else {
1306 of_start =
Matthew McClintockdcf6fd72011-07-18 13:08:05 +00001307 (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
David A. Longd558a4e2011-07-09 16:40:19 -04001308 }
1309 } else {
1310 of_start =
1311 (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
1312 getenv_bootm_mapsize()
1313 + getenv_bootm_low());
1314 }
Kumar Galaa5130ad2008-08-15 08:24:38 -05001315
Timur Tabi6b8f2f82010-05-24 15:10:25 -05001316 if (of_start == 0) {
1317 puts("device tree - allocation error\n");
1318 goto error;
1319 }
Kumar Galaa5130ad2008-08-15 08:24:38 -05001320
David A. Longd558a4e2011-07-09 16:40:19 -04001321 if (disable_relocation) {
1322 /* We assume there is space after the existing fdt to use for padding */
1323 fdt_set_totalsize(of_start, of_len);
1324 printf(" Using Device Tree in place at %p, end %p\n",
1325 of_start, of_start + of_len - 1);
1326 } else {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001327 debug("## device tree at %p ... %p (len=%ld [0x%lX])\n",
David A. Longd558a4e2011-07-09 16:40:19 -04001328 fdt_blob, fdt_blob + *of_size - 1, of_len, of_len);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001329
Stephen Warren6904b6e2011-10-18 11:11:49 +00001330 printf(" Loading Device Tree to %p, end %p ... ",
David A. Longd558a4e2011-07-09 16:40:19 -04001331 of_start, of_start + of_len - 1);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001332
Stephen Warren6904b6e2011-10-18 11:11:49 +00001333 err = fdt_open_into(fdt_blob, of_start, of_len);
David A. Longd558a4e2011-07-09 16:40:19 -04001334 if (err != 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001335 fdt_error("fdt move failed");
David A. Longd558a4e2011-07-09 16:40:19 -04001336 goto error;
1337 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00001338 puts("OK\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001339 }
Timur Tabi6b8f2f82010-05-24 15:10:25 -05001340
1341 *of_flat_tree = of_start;
1342 *of_size = of_len;
Kumar Galaa5130ad2008-08-15 08:24:38 -05001343
Kumar Gala9f4e7e42008-08-15 08:24:39 -05001344 set_working_fdt_addr(*of_flat_tree);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001345 return 0;
1346
1347error:
1348 return 1;
1349}
Grant Likely50fb22e2011-03-28 09:58:49 +00001350#endif /* CONFIG_OF_LIBFDT */
Kumar Galaa5130ad2008-08-15 08:24:38 -05001351
1352/**
1353 * boot_get_fdt - main fdt handling routine
1354 * @argc: command argument count
1355 * @argv: command argument list
1356 * @images: pointer to the bootm images structure
1357 * @of_flat_tree: pointer to a char* variable, will hold fdt start address
1358 * @of_size: pointer to a ulong variable, will hold fdt length
1359 *
1360 * boot_get_fdt() is responsible for finding a valid flat device tree image.
1361 * Curently supported are the following ramdisk sources:
1362 * - multicomponent kernel/ramdisk image,
1363 * - commandline provided address of decicated ramdisk image.
1364 *
1365 * returns:
1366 * 0, if fdt image was found and valid, or skipped
1367 * of_flat_tree and of_size are set to fdt start address and length if
1368 * fdt image is found and valid
1369 *
1370 * 1, if fdt image is found but corrupted
1371 * of_flat_tree and of_size are set to 0 if no fdt exists
1372 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001373int boot_get_fdt(int flag, int argc, char * const argv[],
1374 bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
Kumar Galaa5130ad2008-08-15 08:24:38 -05001375{
Wolfgang Denk3b506772009-08-19 11:42:56 +02001376 const image_header_t *fdt_hdr;
Kumar Galaa5130ad2008-08-15 08:24:38 -05001377 ulong fdt_addr;
Kumar Galaa5130ad2008-08-15 08:24:38 -05001378 char *fdt_blob = NULL;
1379 ulong image_start, image_end;
1380 ulong load_start, load_end;
1381#if defined(CONFIG_FIT)
1382 void *fit_hdr;
1383 const char *fit_uname_config = NULL;
1384 const char *fit_uname_fdt = NULL;
1385 ulong default_addr;
1386 int cfg_noffset;
1387 int fdt_noffset;
1388 const void *data;
1389 size_t size;
1390#endif
1391
1392 *of_flat_tree = NULL;
1393 *of_size = 0;
1394
Stephen Warren6904b6e2011-10-18 11:11:49 +00001395 if (argc > 3 || genimg_has_config(images)) {
Kumar Galaa5130ad2008-08-15 08:24:38 -05001396#if defined(CONFIG_FIT)
1397 if (argc > 3) {
1398 /*
1399 * If the FDT blob comes from the FIT image and the
1400 * FIT image address is omitted in the command line
1401 * argument, try to use ramdisk or os FIT image
1402 * address or default load address.
1403 */
1404 if (images->fit_uname_rd)
1405 default_addr = (ulong)images->fit_hdr_rd;
1406 else if (images->fit_uname_os)
1407 default_addr = (ulong)images->fit_hdr_os;
1408 else
1409 default_addr = load_addr;
1410
Stephen Warren6904b6e2011-10-18 11:11:49 +00001411 if (fit_parse_conf(argv[3], default_addr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001412 &fdt_addr, &fit_uname_config)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001413 debug("* fdt: config '%s' from image at "
1414 "0x%08lx\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001415 fit_uname_config, fdt_addr);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001416 } else if (fit_parse_subimage(argv[3], default_addr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001417 &fdt_addr, &fit_uname_fdt)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001418 debug("* fdt: subimage '%s' from image at "
1419 "0x%08lx\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001420 fit_uname_fdt, fdt_addr);
1421 } else
1422#endif
1423 {
1424 fdt_addr = simple_strtoul(argv[3], NULL, 16);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001425 debug("* fdt: cmdline image address = "
1426 "0x%08lx\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001427 fdt_addr);
1428 }
1429#if defined(CONFIG_FIT)
1430 } else {
1431 /* use FIT configuration provided in first bootm
1432 * command argument
1433 */
1434 fdt_addr = (ulong)images->fit_hdr_os;
1435 fit_uname_config = images->fit_uname_cfg;
Stephen Warren6904b6e2011-10-18 11:11:49 +00001436 debug("* fdt: using config '%s' from image "
1437 "at 0x%08lx\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001438 fit_uname_config, fdt_addr);
1439
1440 /*
1441 * Check whether configuration has FDT blob defined,
1442 * if not quit silently.
1443 */
1444 fit_hdr = (void *)fdt_addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +00001445 cfg_noffset = fit_conf_get_node(fit_hdr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001446 fit_uname_config);
1447 if (cfg_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001448 debug("* fdt: no such config\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001449 return 0;
1450 }
1451
Stephen Warren6904b6e2011-10-18 11:11:49 +00001452 fdt_noffset = fit_conf_get_fdt_node(fit_hdr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001453 cfg_noffset);
1454 if (fdt_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001455 debug("* fdt: no fdt in config\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001456 return 0;
1457 }
1458 }
1459#endif
1460
Stephen Warren6904b6e2011-10-18 11:11:49 +00001461 debug("## Checking for 'FDT'/'FDT Image' at %08lx\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001462 fdt_addr);
1463
1464 /* copy from dataflash if needed */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001465 fdt_addr = genimg_get_image(fdt_addr);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001466
1467 /*
1468 * Check if there is an FDT image at the
1469 * address provided in the second bootm argument
1470 * check image type, for FIT images get a FIT node.
1471 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001472 switch (genimg_get_format((void *)fdt_addr)) {
Kumar Galaa5130ad2008-08-15 08:24:38 -05001473 case IMAGE_FORMAT_LEGACY:
1474 /* verify fdt_addr points to a valid image header */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001475 printf("## Flattened Device Tree from Legacy Image "
1476 "at %08lx\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001477 fdt_addr);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001478 fdt_hdr = image_get_fdt(fdt_addr);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001479 if (!fdt_hdr)
1480 goto error;
1481
1482 /*
1483 * move image data to the load address,
1484 * make sure we don't overwrite initial image
1485 */
1486 image_start = (ulong)fdt_hdr;
Stephen Warren6904b6e2011-10-18 11:11:49 +00001487 image_end = image_get_image_end(fdt_hdr);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001488
Stephen Warren6904b6e2011-10-18 11:11:49 +00001489 load_start = image_get_load(fdt_hdr);
1490 load_end = load_start + image_get_data_size(fdt_hdr);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001491
1492 if ((load_start < image_end) && (load_end > image_start)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001493 fdt_error("fdt overwritten");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001494 goto error;
1495 }
1496
Stephen Warren6904b6e2011-10-18 11:11:49 +00001497 debug(" Loading FDT from 0x%08lx to 0x%08lx\n",
1498 image_get_data(fdt_hdr), load_start);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001499
Stephen Warren6904b6e2011-10-18 11:11:49 +00001500 memmove((void *)load_start,
1501 (void *)image_get_data(fdt_hdr),
1502 image_get_data_size(fdt_hdr));
Kumar Galaa5130ad2008-08-15 08:24:38 -05001503
1504 fdt_blob = (char *)load_start;
1505 break;
1506 case IMAGE_FORMAT_FIT:
1507 /*
1508 * This case will catch both: new uImage format
1509 * (libfdt based) and raw FDT blob (also libfdt
1510 * based).
1511 */
1512#if defined(CONFIG_FIT)
1513 /* check FDT blob vs FIT blob */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001514 if (fit_check_format((const void *)fdt_addr)) {
Kumar Galaa5130ad2008-08-15 08:24:38 -05001515 /*
1516 * FIT image
1517 */
1518 fit_hdr = (void *)fdt_addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +00001519 printf("## Flattened Device Tree from FIT "
1520 "Image at %08lx\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001521 fdt_addr);
1522
1523 if (!fit_uname_fdt) {
1524 /*
1525 * no FDT blob image node unit name,
1526 * try to get config node first. If
1527 * config unit node name is NULL
1528 * fit_conf_get_node() will try to
1529 * find default config node
1530 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001531 cfg_noffset = fit_conf_get_node(fit_hdr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001532 fit_uname_config);
1533
1534 if (cfg_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001535 fdt_error("Could not find "
1536 "configuration "
1537 "node\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001538 goto error;
1539 }
1540
Stephen Warren6904b6e2011-10-18 11:11:49 +00001541 fit_uname_config = fdt_get_name(fit_hdr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001542 cfg_noffset, NULL);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001543 printf(" Using '%s' configuration\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001544 fit_uname_config);
1545
Stephen Warren6904b6e2011-10-18 11:11:49 +00001546 fdt_noffset = fit_conf_get_fdt_node(
1547 fit_hdr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001548 cfg_noffset);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001549 fit_uname_fdt = fit_get_name(fit_hdr,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001550 fdt_noffset, NULL);
1551 } else {
1552 /* get FDT component image node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001553 fdt_noffset = fit_image_get_node(
1554 fit_hdr,
1555 fit_uname_fdt);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001556 }
1557 if (fdt_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001558 fdt_error("Could not find subimage "
1559 "node\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001560 goto error;
1561 }
1562
Stephen Warren6904b6e2011-10-18 11:11:49 +00001563 printf(" Trying '%s' FDT blob subimage\n",
Kumar Galaa5130ad2008-08-15 08:24:38 -05001564 fit_uname_fdt);
1565
Stephen Warren6904b6e2011-10-18 11:11:49 +00001566 if (!fit_check_fdt(fit_hdr, fdt_noffset,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001567 images->verify))
1568 goto error;
1569
1570 /* get ramdisk image data address and length */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001571 if (fit_image_get_data(fit_hdr, fdt_noffset,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001572 &data, &size)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001573 fdt_error("Could not find FDT "
1574 "subimage data");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001575 goto error;
1576 }
1577
1578 /* verift that image data is a proper FDT blob */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001579 if (fdt_check_header((char *)data) != 0) {
1580 fdt_error("Subimage data is not a FTD");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001581 goto error;
1582 }
1583
1584 /*
1585 * move image data to the load address,
1586 * make sure we don't overwrite initial image
1587 */
1588 image_start = (ulong)fit_hdr;
Stephen Warren6904b6e2011-10-18 11:11:49 +00001589 image_end = fit_get_end(fit_hdr);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001590
Stephen Warren6904b6e2011-10-18 11:11:49 +00001591 if (fit_image_get_load(fit_hdr, fdt_noffset,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001592 &load_start) == 0) {
1593 load_end = load_start + size;
1594
1595 if ((load_start < image_end) &&
1596 (load_end > image_start)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001597 fdt_error("FDT overwritten");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001598 goto error;
1599 }
1600
Stephen Warren6904b6e2011-10-18 11:11:49 +00001601 printf(" Loading FDT from 0x%08lx "
1602 "to 0x%08lx\n",
1603 (ulong)data,
1604 load_start);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001605
Stephen Warren6904b6e2011-10-18 11:11:49 +00001606 memmove((void *)load_start,
Kumar Galaa5130ad2008-08-15 08:24:38 -05001607 (void *)data, size);
1608
1609 fdt_blob = (char *)load_start;
1610 } else {
1611 fdt_blob = (char *)data;
1612 }
1613
1614 images->fit_hdr_fdt = fit_hdr;
1615 images->fit_uname_fdt = fit_uname_fdt;
1616 images->fit_noffset_fdt = fdt_noffset;
1617 break;
1618 } else
1619#endif
1620 {
1621 /*
1622 * FDT blob
1623 */
1624 fdt_blob = (char *)fdt_addr;
Stephen Warren6904b6e2011-10-18 11:11:49 +00001625 debug("* fdt: raw FDT blob\n");
1626 printf("## Flattened Device Tree blob at "
1627 "%08lx\n", (long)fdt_blob);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001628 }
1629 break;
1630 default:
Stephen Warren6904b6e2011-10-18 11:11:49 +00001631 puts("ERROR: Did not find a cmdline Flattened Device "
1632 "Tree\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001633 goto error;
1634 }
1635
Simon Glass00aa9882011-09-23 06:22:04 +00001636 printf(" Booting using the fdt blob at 0x%p\n", fdt_blob);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001637
1638 } else if (images->legacy_hdr_valid &&
Stephen Warren6904b6e2011-10-18 11:11:49 +00001639 image_check_type(&images->legacy_hdr_os_copy,
1640 IH_TYPE_MULTI)) {
Kumar Galaa5130ad2008-08-15 08:24:38 -05001641
1642 ulong fdt_data, fdt_len;
1643
1644 /*
1645 * Now check if we have a legacy multi-component image,
1646 * get second entry data start address and len.
1647 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001648 printf("## Flattened Device Tree from multi "
Kumar Galaa5130ad2008-08-15 08:24:38 -05001649 "component Image at %08lX\n",
1650 (ulong)images->legacy_hdr_os);
1651
Stephen Warren6904b6e2011-10-18 11:11:49 +00001652 image_multi_getimg(images->legacy_hdr_os, 2, &fdt_data,
1653 &fdt_len);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001654 if (fdt_len) {
1655
1656 fdt_blob = (char *)fdt_data;
Simon Glass00aa9882011-09-23 06:22:04 +00001657 printf(" Booting using the fdt at 0x%p\n", fdt_blob);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001658
Stephen Warren6904b6e2011-10-18 11:11:49 +00001659 if (fdt_check_header(fdt_blob) != 0) {
1660 fdt_error("image is not a fdt");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001661 goto error;
1662 }
1663
John Rigbyb763f932010-10-13 13:57:32 -06001664 if (fdt_totalsize(fdt_blob) != fdt_len) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001665 fdt_error("fdt size != image size");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001666 goto error;
1667 }
1668 } else {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001669 debug("## No Flattened Device Tree\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001670 return 0;
1671 }
1672 } else {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001673 debug("## No Flattened Device Tree\n");
Kumar Galaa5130ad2008-08-15 08:24:38 -05001674 return 0;
1675 }
1676
1677 *of_flat_tree = fdt_blob;
John Rigbyb763f932010-10-13 13:57:32 -06001678 *of_size = fdt_totalsize(fdt_blob);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001679 debug(" of_flat_tree at 0x%08lx size 0x%08lx\n",
Andrew Klossner7ddfafc2008-08-21 07:12:26 -07001680 (ulong)*of_flat_tree, *of_size);
Kumar Galaa5130ad2008-08-15 08:24:38 -05001681
1682 return 0;
1683
1684error:
1685 *of_flat_tree = 0;
1686 *of_size = 0;
1687 return 1;
1688}
1689#endif /* CONFIG_OF_LIBFDT */
1690
John Rigbyeea8e692010-10-13 13:57:35 -06001691#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001692/**
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001693 * boot_get_cmdline - allocate and initialize kernel cmdline
Kumar Galab937bb72008-02-27 21:51:49 -06001694 * @lmb: pointer to lmb handle, will be used for memory mgmt
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001695 * @cmd_start: pointer to a ulong variable, will hold cmdline start
1696 * @cmd_end: pointer to a ulong variable, will hold cmdline end
1697 *
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001698 * boot_get_cmdline() allocates space for kernel command line below
Grant Likelydfff7a22011-03-28 09:58:34 +00001699 * BOOTMAPSZ + getenv_bootm_low() address. If "bootargs" U-boot environemnt
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001700 * variable is present its contents is copied to allocated kernel
1701 * command line.
1702 *
1703 * returns:
Kumar Galab937bb72008-02-27 21:51:49 -06001704 * 0 - success
1705 * -1 - failure
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001706 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001707int boot_get_cmdline(struct lmb *lmb, ulong *cmd_start, ulong *cmd_end)
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001708{
1709 char *cmdline;
1710 char *s;
1711
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001712 cmdline = (char *)(ulong)lmb_alloc_base(lmb, CONFIG_SYS_BARGSIZE, 0xf,
Grant Likely26396382011-03-28 09:58:43 +00001713 getenv_bootm_mapsize() + getenv_bootm_low());
Kumar Galab937bb72008-02-27 21:51:49 -06001714
1715 if (cmdline == NULL)
1716 return -1;
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001717
1718 if ((s = getenv("bootargs")) == NULL)
1719 s = "";
1720
1721 strcpy(cmdline, s);
1722
1723 *cmd_start = (ulong) & cmdline[0];
1724 *cmd_end = *cmd_start + strlen(cmdline);
1725
Stephen Warren6904b6e2011-10-18 11:11:49 +00001726 debug("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end);
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001727
Kumar Galab937bb72008-02-27 21:51:49 -06001728 return 0;
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001729}
John Rigbyeea8e692010-10-13 13:57:35 -06001730#endif /* CONFIG_SYS_BOOT_GET_CMDLINE */
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001731
John Rigbyeea8e692010-10-13 13:57:35 -06001732#ifdef CONFIG_SYS_BOOT_GET_KBD
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001733/**
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001734 * boot_get_kbd - allocate and initialize kernel copy of board info
Kumar Galab937bb72008-02-27 21:51:49 -06001735 * @lmb: pointer to lmb handle, will be used for memory mgmt
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001736 * @kbd: double pointer to board info data
1737 *
Marian Balakowiczd7c88a42008-02-29 14:58:34 +01001738 * boot_get_kbd() allocates space for kernel copy of board info data below
Grant Likelydfff7a22011-03-28 09:58:34 +00001739 * BOOTMAPSZ + getenv_bootm_low() address and kernel board info is initialized
1740 * with the current u-boot board info data.
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001741 *
1742 * returns:
Kumar Galab937bb72008-02-27 21:51:49 -06001743 * 0 - success
1744 * -1 - failure
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001745 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001746int boot_get_kbd(struct lmb *lmb, bd_t **kbd)
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001747{
Becky Bruced26d67c2008-06-09 20:37:18 -05001748 *kbd = (bd_t *)(ulong)lmb_alloc_base(lmb, sizeof(bd_t), 0xf,
Grant Likely26396382011-03-28 09:58:43 +00001749 getenv_bootm_mapsize() + getenv_bootm_low());
Kumar Galab937bb72008-02-27 21:51:49 -06001750 if (*kbd == NULL)
1751 return -1;
1752
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001753 **kbd = *(gd->bd);
1754
Stephen Warren6904b6e2011-10-18 11:11:49 +00001755 debug("## kernel board info at 0x%08lx\n", (ulong)*kbd);
Marian Balakowicz2efc2642008-01-31 13:58:13 +01001756
1757#if defined(DEBUG) && defined(CONFIG_CMD_BDI)
1758 do_bdinfo(NULL, 0, 0, NULL);
1759#endif
1760
Kumar Galab937bb72008-02-27 21:51:49 -06001761 return 0;
Marian Balakowicz9c701e82008-01-31 13:57:17 +01001762}
John Rigbyeea8e692010-10-13 13:57:35 -06001763#endif /* CONFIG_SYS_BOOT_GET_KBD */
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001764#endif /* !USE_HOSTCC */
Marian Balakowicz95418502008-01-31 13:55:39 +01001765
Marian Balakowicz3413e222008-02-21 17:20:20 +01001766#if defined(CONFIG_FIT)
1767/*****************************************************************************/
1768/* New uImage format routines */
1769/*****************************************************************************/
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001770#ifndef USE_HOSTCC
Stephen Warren6904b6e2011-10-18 11:11:49 +00001771static int fit_parse_spec(const char *spec, char sepc, ulong addr_curr,
Marian Balakowicz3413e222008-02-21 17:20:20 +01001772 ulong *addr, const char **name)
1773{
1774 const char *sep;
1775
1776 *addr = addr_curr;
1777 *name = NULL;
1778
Stephen Warren6904b6e2011-10-18 11:11:49 +00001779 sep = strchr(spec, sepc);
Marian Balakowicz3413e222008-02-21 17:20:20 +01001780 if (sep) {
1781 if (sep - spec > 0)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001782 *addr = simple_strtoul(spec, NULL, 16);
Marian Balakowicz3413e222008-02-21 17:20:20 +01001783
1784 *name = sep + 1;
1785 return 1;
1786 }
1787
1788 return 0;
1789}
1790
1791/**
1792 * fit_parse_conf - parse FIT configuration spec
1793 * @spec: input string, containing configuration spec
1794 * @add_curr: current image address (to be used as a possible default)
1795 * @addr: pointer to a ulong variable, will hold FIT image address of a given
1796 * configuration
1797 * @conf_name double pointer to a char, will hold pointer to a configuration
1798 * unit name
1799 *
1800 * fit_parse_conf() expects configuration spec in the for of [<addr>]#<conf>,
1801 * where <addr> is a FIT image address that contains configuration
1802 * with a <conf> unit name.
1803 *
1804 * Address part is optional, and if omitted default add_curr will
1805 * be used instead.
1806 *
1807 * returns:
1808 * 1 if spec is a valid configuration string,
1809 * addr and conf_name are set accordingly
1810 * 0 otherwise
1811 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001812inline int fit_parse_conf(const char *spec, ulong addr_curr,
Marian Balakowicz3413e222008-02-21 17:20:20 +01001813 ulong *addr, const char **conf_name)
1814{
Stephen Warren6904b6e2011-10-18 11:11:49 +00001815 return fit_parse_spec(spec, '#', addr_curr, addr, conf_name);
Marian Balakowicz3413e222008-02-21 17:20:20 +01001816}
1817
1818/**
1819 * fit_parse_subimage - parse FIT subimage spec
1820 * @spec: input string, containing subimage spec
1821 * @add_curr: current image address (to be used as a possible default)
1822 * @addr: pointer to a ulong variable, will hold FIT image address of a given
1823 * subimage
1824 * @image_name: double pointer to a char, will hold pointer to a subimage name
1825 *
1826 * fit_parse_subimage() expects subimage spec in the for of
1827 * [<addr>]:<subimage>, where <addr> is a FIT image address that contains
1828 * subimage with a <subimg> unit name.
1829 *
1830 * Address part is optional, and if omitted default add_curr will
1831 * be used instead.
1832 *
1833 * returns:
1834 * 1 if spec is a valid subimage string,
1835 * addr and image_name are set accordingly
1836 * 0 otherwise
1837 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001838inline int fit_parse_subimage(const char *spec, ulong addr_curr,
Marian Balakowicz3413e222008-02-21 17:20:20 +01001839 ulong *addr, const char **image_name)
1840{
Stephen Warren6904b6e2011-10-18 11:11:49 +00001841 return fit_parse_spec(spec, ':', addr_curr, addr, image_name);
Marian Balakowicz3413e222008-02-21 17:20:20 +01001842}
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001843#endif /* !USE_HOSTCC */
1844
Stephen Warren6904b6e2011-10-18 11:11:49 +00001845static void fit_get_debug(const void *fit, int noffset,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001846 char *prop_name, int err)
1847{
Stephen Warren6904b6e2011-10-18 11:11:49 +00001848 debug("Can't get '%s' property from FIT 0x%08lx, "
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001849 "node: offset %d, name %s (%s)\n",
1850 prop_name, (ulong)fit, noffset,
Stephen Warren6904b6e2011-10-18 11:11:49 +00001851 fit_get_name(fit, noffset, NULL),
1852 fdt_strerror(err));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001853}
1854
1855/**
Bartlomiej Sieka47868592008-04-18 12:39:23 +02001856 * fit_print_contents - prints out the contents of the FIT format image
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001857 * @fit: pointer to the FIT format image header
1858 * @p: pointer to prefix string
1859 *
Bartlomiej Sieka47868592008-04-18 12:39:23 +02001860 * fit_print_contents() formats a multi line FIT image contents description.
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001861 * The routine prints out FIT image properties (root node level) follwed by
1862 * the details of each component image.
1863 *
1864 * returns:
1865 * no returned results
1866 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001867void fit_print_contents(const void *fit)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001868{
1869 char *desc;
1870 char *uname;
1871 int images_noffset;
1872 int confs_noffset;
1873 int noffset;
1874 int ndepth;
1875 int count = 0;
1876 int ret;
Bartlomiej Sieka47868592008-04-18 12:39:23 +02001877 const char *p;
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001878#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
1879 time_t timestamp;
1880#endif
1881
Bartlomiej Sieka47868592008-04-18 12:39:23 +02001882#ifdef USE_HOSTCC
1883 p = "";
1884#else
1885 p = " ";
1886#endif
1887
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001888 /* Root node properties */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001889 ret = fit_get_desc(fit, 0, &desc);
1890 printf("%sFIT description: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001891 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001892 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001893 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00001894 printf("%s\n", desc);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001895
1896#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001897 ret = fit_get_timestamp(fit, 0, &timestamp);
1898 printf("%sCreated: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001899 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001900 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001901 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00001902 genimg_print_time(timestamp);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001903#endif
1904
1905 /* Find images parent node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001906 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001907 if (images_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001908 printf("Can't find images parent node '%s' (%s)\n",
1909 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001910 return;
1911 }
1912
1913 /* Process its subnodes, print out component images details */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001914 for (ndepth = 0, count = 0,
1915 noffset = fdt_next_node(fit, images_noffset, &ndepth);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001916 (noffset >= 0) && (ndepth > 0);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001917 noffset = fdt_next_node(fit, noffset, &ndepth)) {
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001918 if (ndepth == 1) {
1919 /*
1920 * Direct child node of the images parent node,
1921 * i.e. component image node.
1922 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001923 printf("%s Image %u (%s)\n", p, count++,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001924 fit_get_name(fit, noffset, NULL));
1925
Stephen Warren6904b6e2011-10-18 11:11:49 +00001926 fit_image_print(fit, noffset, p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001927 }
1928 }
1929
1930 /* Find configurations parent node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001931 confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001932 if (confs_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00001933 debug("Can't get configurations parent node '%s' (%s)\n",
1934 FIT_CONFS_PATH, fdt_strerror(confs_noffset));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001935 return;
1936 }
1937
1938 /* get default configuration unit name from default property */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001939 uname = (char *)fdt_getprop(fit, noffset, FIT_DEFAULT_PROP, NULL);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001940 if (uname)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001941 printf("%s Default Configuration: '%s'\n", p, uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001942
1943 /* Process its subnodes, print out configurations details */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001944 for (ndepth = 0, count = 0,
1945 noffset = fdt_next_node(fit, confs_noffset, &ndepth);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001946 (noffset >= 0) && (ndepth > 0);
Stephen Warren6904b6e2011-10-18 11:11:49 +00001947 noffset = fdt_next_node(fit, noffset, &ndepth)) {
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001948 if (ndepth == 1) {
1949 /*
1950 * Direct child node of the configurations parent node,
1951 * i.e. configuration node.
1952 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001953 printf("%s Configuration %u (%s)\n", p, count++,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001954 fit_get_name(fit, noffset, NULL));
1955
Stephen Warren6904b6e2011-10-18 11:11:49 +00001956 fit_conf_print(fit, noffset, p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001957 }
1958 }
1959}
1960
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001961/**
1962 * fit_image_print - prints out the FIT component image details
1963 * @fit: pointer to the FIT format image header
1964 * @image_noffset: offset of the component image node
1965 * @p: pointer to prefix string
1966 *
1967 * fit_image_print() lists all mandatory properies for the processed component
Bartlomiej Sieka0cc0b212008-10-01 15:26:32 +02001968 * image. If present, hash nodes are printed out as well. Load
1969 * address for images of type firmware is also printed out. Since the load
1970 * address is not mandatory for firmware images, it will be output as
1971 * "unavailable" when not present.
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001972 *
1973 * returns:
1974 * no returned results
1975 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001976void fit_image_print(const void *fit, int image_noffset, const char *p)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001977{
1978 char *desc;
1979 uint8_t type, arch, os, comp;
1980 size_t size;
1981 ulong load, entry;
1982 const void *data;
1983 int noffset;
1984 int ndepth;
1985 int ret;
1986
1987 /* Mandatory properties */
Stephen Warren6904b6e2011-10-18 11:11:49 +00001988 ret = fit_get_desc(fit, image_noffset, &desc);
1989 printf("%s Description: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001990 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00001991 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001992 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00001993 printf("%s\n", desc);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001994
Stephen Warren6904b6e2011-10-18 11:11:49 +00001995 fit_image_get_type(fit, image_noffset, &type);
1996 printf("%s Type: %s\n", p, genimg_get_type_name(type));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01001997
Stephen Warren6904b6e2011-10-18 11:11:49 +00001998 fit_image_get_comp(fit, image_noffset, &comp);
1999 printf("%s Compression: %s\n", p, genimg_get_comp_name(comp));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002000
Stephen Warren6904b6e2011-10-18 11:11:49 +00002001 ret = fit_image_get_data(fit, image_noffset, &data, &size);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002002
2003#ifndef USE_HOSTCC
Stephen Warren6904b6e2011-10-18 11:11:49 +00002004 printf("%s Data Start: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002005 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00002006 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002007 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00002008 printf("0x%08lx\n", (ulong)data);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002009#endif
2010
Stephen Warren6904b6e2011-10-18 11:11:49 +00002011 printf("%s Data Size: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002012 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00002013 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002014 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00002015 genimg_print_size(size);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002016
2017 /* Remaining, type dependent properties */
2018 if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
2019 (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) ||
2020 (type == IH_TYPE_FLATDT)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002021 fit_image_get_arch(fit, image_noffset, &arch);
2022 printf("%s Architecture: %s\n", p, genimg_get_arch_name(arch));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002023 }
2024
2025 if (type == IH_TYPE_KERNEL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002026 fit_image_get_os(fit, image_noffset, &os);
2027 printf("%s OS: %s\n", p, genimg_get_os_name(os));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002028 }
2029
Bartlomiej Sieka0cc0b212008-10-01 15:26:32 +02002030 if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
2031 (type == IH_TYPE_FIRMWARE)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002032 ret = fit_image_get_load(fit, image_noffset, &load);
2033 printf("%s Load Address: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002034 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00002035 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002036 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00002037 printf("0x%08lx\n", load);
Bartlomiej Sieka0cc0b212008-10-01 15:26:32 +02002038 }
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002039
Bartlomiej Sieka0cc0b212008-10-01 15:26:32 +02002040 if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002041 fit_image_get_entry(fit, image_noffset, &entry);
2042 printf("%s Entry Point: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002043 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00002044 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002045 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00002046 printf("0x%08lx\n", entry);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002047 }
2048
2049 /* Process all hash subnodes of the component image node */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002050 for (ndepth = 0, noffset = fdt_next_node(fit, image_noffset, &ndepth);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002051 (noffset >= 0) && (ndepth > 0);
Stephen Warren6904b6e2011-10-18 11:11:49 +00002052 noffset = fdt_next_node(fit, noffset, &ndepth)) {
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002053 if (ndepth == 1) {
2054 /* Direct child node of the component image node */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002055 fit_image_print_hash(fit, noffset, p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002056 }
2057 }
2058}
2059
2060/**
2061 * fit_image_print_hash - prints out the hash node details
2062 * @fit: pointer to the FIT format image header
2063 * @noffset: offset of the hash node
2064 * @p: pointer to prefix string
2065 *
2066 * fit_image_print_hash() lists properies for the processed hash node
2067 *
2068 * returns:
2069 * no returned results
2070 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002071void fit_image_print_hash(const void *fit, int noffset, const char *p)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002072{
2073 char *algo;
2074 uint8_t *value;
2075 int value_len;
2076 int i, ret;
2077
2078 /*
2079 * Check subnode name, must be equal to "hash".
2080 * Multiple hash nodes require unique unit node
2081 * names, e.g. hash@1, hash@2, etc.
2082 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002083 if (strncmp(fit_get_name(fit, noffset, NULL),
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002084 FIT_HASH_NODENAME,
2085 strlen(FIT_HASH_NODENAME)) != 0)
2086 return;
2087
Stephen Warren6904b6e2011-10-18 11:11:49 +00002088 debug("%s Hash node: '%s'\n", p,
2089 fit_get_name(fit, noffset, NULL));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002090
Stephen Warren6904b6e2011-10-18 11:11:49 +00002091 printf("%s Hash algo: ", p);
2092 if (fit_image_hash_get_algo(fit, noffset, &algo)) {
2093 printf("invalid/unsupported\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002094 return;
2095 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00002096 printf("%s\n", algo);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002097
Stephen Warren6904b6e2011-10-18 11:11:49 +00002098 ret = fit_image_hash_get_value(fit, noffset, &value,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002099 &value_len);
Stephen Warren6904b6e2011-10-18 11:11:49 +00002100 printf("%s Hash value: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002101 if (ret) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002102 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002103 } else {
2104 for (i = 0; i < value_len; i++)
Stephen Warren6904b6e2011-10-18 11:11:49 +00002105 printf("%02x", value[i]);
2106 printf("\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002107 }
2108
Stephen Warren6904b6e2011-10-18 11:11:49 +00002109 debug("%s Hash len: %d\n", p, value_len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002110}
2111
2112/**
2113 * fit_get_desc - get node description property
2114 * @fit: pointer to the FIT format image header
2115 * @noffset: node offset
2116 * @desc: double pointer to the char, will hold pointer to the descrption
2117 *
2118 * fit_get_desc() reads description property from a given node, if
2119 * description is found pointer to it is returened in third call argument.
2120 *
2121 * returns:
2122 * 0, on success
2123 * -1, on failure
2124 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002125int fit_get_desc(const void *fit, int noffset, char **desc)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002126{
2127 int len;
2128
Stephen Warren6904b6e2011-10-18 11:11:49 +00002129 *desc = (char *)fdt_getprop(fit, noffset, FIT_DESC_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002130 if (*desc == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002131 fit_get_debug(fit, noffset, FIT_DESC_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002132 return -1;
2133 }
2134
2135 return 0;
2136}
2137
2138/**
2139 * fit_get_timestamp - get node timestamp property
2140 * @fit: pointer to the FIT format image header
2141 * @noffset: node offset
2142 * @timestamp: pointer to the time_t, will hold read timestamp
2143 *
2144 * fit_get_timestamp() reads timestamp poperty from given node, if timestamp
2145 * is found and has a correct size its value is retured in third call
2146 * argument.
2147 *
2148 * returns:
2149 * 0, on success
2150 * -1, on property read failure
2151 * -2, on wrong timestamp size
2152 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002153int fit_get_timestamp(const void *fit, int noffset, time_t *timestamp)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002154{
2155 int len;
2156 const void *data;
2157
Stephen Warren6904b6e2011-10-18 11:11:49 +00002158 data = fdt_getprop(fit, noffset, FIT_TIMESTAMP_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002159 if (data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002160 fit_get_debug(fit, noffset, FIT_TIMESTAMP_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002161 return -1;
2162 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00002163 if (len != sizeof(uint32_t)) {
2164 debug("FIT timestamp with incorrect size of (%u)\n", len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002165 return -2;
2166 }
2167
Stephen Warren6904b6e2011-10-18 11:11:49 +00002168 *timestamp = uimage_to_cpu(*((uint32_t *)data));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002169 return 0;
2170}
2171
2172/**
2173 * fit_image_get_node - get node offset for component image of a given unit name
2174 * @fit: pointer to the FIT format image header
2175 * @image_uname: component image node unit name
2176 *
2177 * fit_image_get_node() finds a component image (withing the '/images'
2178 * node) of a provided unit name. If image is found its node offset is
2179 * returned to the caller.
2180 *
2181 * returns:
2182 * image node offset when found (>=0)
2183 * negative number on failure (FDT_ERR_* code)
2184 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002185int fit_image_get_node(const void *fit, const char *image_uname)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002186{
2187 int noffset, images_noffset;
2188
Stephen Warren6904b6e2011-10-18 11:11:49 +00002189 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002190 if (images_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002191 debug("Can't find images parent node '%s' (%s)\n",
2192 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002193 return images_noffset;
2194 }
2195
Stephen Warren6904b6e2011-10-18 11:11:49 +00002196 noffset = fdt_subnode_offset(fit, images_noffset, image_uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002197 if (noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002198 debug("Can't get node offset for image unit name: '%s' (%s)\n",
2199 image_uname, fdt_strerror(noffset));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002200 }
2201
2202 return noffset;
2203}
2204
2205/**
2206 * fit_image_get_os - get os id for a given component image node
2207 * @fit: pointer to the FIT format image header
2208 * @noffset: component image node offset
2209 * @os: pointer to the uint8_t, will hold os numeric id
2210 *
2211 * fit_image_get_os() finds os property in a given component image node.
2212 * If the property is found, its (string) value is translated to the numeric
2213 * id which is returned to the caller.
2214 *
2215 * returns:
2216 * 0, on success
2217 * -1, on failure
2218 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002219int fit_image_get_os(const void *fit, int noffset, uint8_t *os)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002220{
2221 int len;
2222 const void *data;
2223
2224 /* Get OS name from property data */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002225 data = fdt_getprop(fit, noffset, FIT_OS_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002226 if (data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002227 fit_get_debug(fit, noffset, FIT_OS_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002228 *os = -1;
2229 return -1;
2230 }
2231
2232 /* Translate OS name to id */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002233 *os = genimg_get_os_id(data);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002234 return 0;
2235}
2236
2237/**
2238 * fit_image_get_arch - get arch id for a given component image node
2239 * @fit: pointer to the FIT format image header
2240 * @noffset: component image node offset
2241 * @arch: pointer to the uint8_t, will hold arch numeric id
2242 *
2243 * fit_image_get_arch() finds arch property in a given component image node.
2244 * If the property is found, its (string) value is translated to the numeric
2245 * id which is returned to the caller.
2246 *
2247 * returns:
2248 * 0, on success
2249 * -1, on failure
2250 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002251int fit_image_get_arch(const void *fit, int noffset, uint8_t *arch)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002252{
2253 int len;
2254 const void *data;
2255
2256 /* Get architecture name from property data */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002257 data = fdt_getprop(fit, noffset, FIT_ARCH_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002258 if (data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002259 fit_get_debug(fit, noffset, FIT_ARCH_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002260 *arch = -1;
2261 return -1;
2262 }
2263
2264 /* Translate architecture name to id */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002265 *arch = genimg_get_arch_id(data);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002266 return 0;
2267}
2268
2269/**
2270 * fit_image_get_type - get type id for a given component image node
2271 * @fit: pointer to the FIT format image header
2272 * @noffset: component image node offset
2273 * @type: pointer to the uint8_t, will hold type numeric id
2274 *
2275 * fit_image_get_type() finds type property in a given component image node.
2276 * If the property is found, its (string) value is translated to the numeric
2277 * id which is returned to the caller.
2278 *
2279 * returns:
2280 * 0, on success
2281 * -1, on failure
2282 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002283int fit_image_get_type(const void *fit, int noffset, uint8_t *type)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002284{
2285 int len;
2286 const void *data;
2287
2288 /* Get image type name from property data */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002289 data = fdt_getprop(fit, noffset, FIT_TYPE_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002290 if (data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002291 fit_get_debug(fit, noffset, FIT_TYPE_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002292 *type = -1;
2293 return -1;
2294 }
2295
2296 /* Translate image type name to id */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002297 *type = genimg_get_type_id(data);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002298 return 0;
2299}
2300
2301/**
2302 * fit_image_get_comp - get comp id for a given component image node
2303 * @fit: pointer to the FIT format image header
2304 * @noffset: component image node offset
2305 * @comp: pointer to the uint8_t, will hold comp numeric id
2306 *
2307 * fit_image_get_comp() finds comp property in a given component image node.
2308 * If the property is found, its (string) value is translated to the numeric
2309 * id which is returned to the caller.
2310 *
2311 * returns:
2312 * 0, on success
2313 * -1, on failure
2314 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002315int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002316{
2317 int len;
2318 const void *data;
2319
2320 /* Get compression name from property data */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002321 data = fdt_getprop(fit, noffset, FIT_COMP_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002322 if (data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002323 fit_get_debug(fit, noffset, FIT_COMP_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002324 *comp = -1;
2325 return -1;
2326 }
2327
2328 /* Translate compression name to id */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002329 *comp = genimg_get_comp_id(data);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002330 return 0;
2331}
2332
2333/**
2334 * fit_image_get_load - get load address property for a given component image node
2335 * @fit: pointer to the FIT format image header
2336 * @noffset: component image node offset
2337 * @load: pointer to the uint32_t, will hold load address
2338 *
2339 * fit_image_get_load() finds load address property in a given component image node.
2340 * If the property is found, its value is returned to the caller.
2341 *
2342 * returns:
2343 * 0, on success
2344 * -1, on failure
2345 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002346int fit_image_get_load(const void *fit, int noffset, ulong *load)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002347{
2348 int len;
2349 const uint32_t *data;
2350
Stephen Warren6904b6e2011-10-18 11:11:49 +00002351 data = fdt_getprop(fit, noffset, FIT_LOAD_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002352 if (data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002353 fit_get_debug(fit, noffset, FIT_LOAD_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002354 return -1;
2355 }
2356
Stephen Warren6904b6e2011-10-18 11:11:49 +00002357 *load = uimage_to_cpu(*data);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002358 return 0;
2359}
2360
2361/**
2362 * fit_image_get_entry - get entry point address property for a given component image node
2363 * @fit: pointer to the FIT format image header
2364 * @noffset: component image node offset
2365 * @entry: pointer to the uint32_t, will hold entry point address
2366 *
2367 * fit_image_get_entry() finds entry point address property in a given component image node.
2368 * If the property is found, its value is returned to the caller.
2369 *
2370 * returns:
2371 * 0, on success
2372 * -1, on failure
2373 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002374int fit_image_get_entry(const void *fit, int noffset, ulong *entry)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002375{
2376 int len;
2377 const uint32_t *data;
2378
Stephen Warren6904b6e2011-10-18 11:11:49 +00002379 data = fdt_getprop(fit, noffset, FIT_ENTRY_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002380 if (data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002381 fit_get_debug(fit, noffset, FIT_ENTRY_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002382 return -1;
2383 }
2384
Stephen Warren6904b6e2011-10-18 11:11:49 +00002385 *entry = uimage_to_cpu(*data);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002386 return 0;
2387}
2388
2389/**
2390 * fit_image_get_data - get data property and its size for a given component image node
2391 * @fit: pointer to the FIT format image header
2392 * @noffset: component image node offset
2393 * @data: double pointer to void, will hold data property's data address
2394 * @size: pointer to size_t, will hold data property's data size
2395 *
2396 * fit_image_get_data() finds data property in a given component image node.
2397 * If the property is found its data start address and size are returned to
2398 * the caller.
2399 *
2400 * returns:
2401 * 0, on success
2402 * -1, on failure
2403 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002404int fit_image_get_data(const void *fit, int noffset,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002405 const void **data, size_t *size)
2406{
2407 int len;
2408
Stephen Warren6904b6e2011-10-18 11:11:49 +00002409 *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002410 if (*data == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002411 fit_get_debug(fit, noffset, FIT_DATA_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002412 *size = 0;
2413 return -1;
2414 }
2415
2416 *size = len;
2417 return 0;
2418}
2419
2420/**
2421 * fit_image_hash_get_algo - get hash algorithm name
2422 * @fit: pointer to the FIT format image header
2423 * @noffset: hash node offset
2424 * @algo: double pointer to char, will hold pointer to the algorithm name
2425 *
2426 * fit_image_hash_get_algo() finds hash algorithm property in a given hash node.
2427 * If the property is found its data start address is returned to the caller.
2428 *
2429 * returns:
2430 * 0, on success
2431 * -1, on failure
2432 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002433int fit_image_hash_get_algo(const void *fit, int noffset, char **algo)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002434{
2435 int len;
2436
Stephen Warren6904b6e2011-10-18 11:11:49 +00002437 *algo = (char *)fdt_getprop(fit, noffset, FIT_ALGO_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002438 if (*algo == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002439 fit_get_debug(fit, noffset, FIT_ALGO_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002440 return -1;
2441 }
2442
2443 return 0;
2444}
2445
2446/**
2447 * fit_image_hash_get_value - get hash value and length
2448 * @fit: pointer to the FIT format image header
2449 * @noffset: hash node offset
2450 * @value: double pointer to uint8_t, will hold address of a hash value data
2451 * @value_len: pointer to an int, will hold hash data length
2452 *
2453 * fit_image_hash_get_value() finds hash value property in a given hash node.
2454 * If the property is found its data start address and size are returned to
2455 * the caller.
2456 *
2457 * returns:
2458 * 0, on success
2459 * -1, on failure
2460 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002461int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002462 int *value_len)
2463{
2464 int len;
2465
Stephen Warren6904b6e2011-10-18 11:11:49 +00002466 *value = (uint8_t *)fdt_getprop(fit, noffset, FIT_VALUE_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002467 if (*value == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002468 fit_get_debug(fit, noffset, FIT_VALUE_PROP, len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002469 *value_len = 0;
2470 return -1;
2471 }
2472
2473 *value_len = len;
2474 return 0;
2475}
2476
2477/**
2478 * fit_set_timestamp - set node timestamp property
2479 * @fit: pointer to the FIT format image header
2480 * @noffset: node offset
2481 * @timestamp: timestamp value to be set
2482 *
2483 * fit_set_timestamp() attempts to set timestamp property in the requested
2484 * node and returns operation status to the caller.
2485 *
2486 * returns:
2487 * 0, on success
2488 * -1, on property read failure
2489 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002490int fit_set_timestamp(void *fit, int noffset, time_t timestamp)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002491{
2492 uint32_t t;
2493 int ret;
2494
Stephen Warren6904b6e2011-10-18 11:11:49 +00002495 t = cpu_to_uimage(timestamp);
2496 ret = fdt_setprop(fit, noffset, FIT_TIMESTAMP_PROP, &t,
2497 sizeof(uint32_t));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002498 if (ret) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002499 printf("Can't set '%s' property for '%s' node (%s)\n",
2500 FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset, NULL),
2501 fdt_strerror(ret));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002502 return -1;
2503 }
2504
2505 return 0;
2506}
2507
2508/**
2509 * calculate_hash - calculate and return hash for provided input data
2510 * @data: pointer to the input data
2511 * @data_len: data length
2512 * @algo: requested hash algorithm
2513 * @value: pointer to the char, will hold hash value data (caller must
2514 * allocate enough free space)
2515 * value_len: length of the calculated hash
2516 *
2517 * calculate_hash() computes input data hash according to the requested algorithm.
2518 * Resulting hash value is placed in caller provided 'value' buffer, length
2519 * of the calculated hash is returned via value_len pointer argument.
2520 *
2521 * returns:
2522 * 0, on success
2523 * -1, when algo is unsupported
2524 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002525static int calculate_hash(const void *data, int data_len, const char *algo,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002526 uint8_t *value, int *value_len)
2527{
Stephen Warren6904b6e2011-10-18 11:11:49 +00002528 if (strcmp(algo, "crc32") == 0) {
2529 *((uint32_t *)value) = crc32_wd(0, data, data_len,
Bartlomiej Sieka222e2ca2008-04-25 13:54:02 +02002530 CHUNKSZ_CRC32);
Stephen Warren6904b6e2011-10-18 11:11:49 +00002531 *((uint32_t *)value) = cpu_to_uimage(*((uint32_t *)value));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002532 *value_len = 4;
Stephen Warren6904b6e2011-10-18 11:11:49 +00002533 } else if (strcmp(algo, "sha1") == 0) {
2534 sha1_csum_wd((unsigned char *) data, data_len,
Bartlomiej Sieka222e2ca2008-04-25 13:54:02 +02002535 (unsigned char *) value, CHUNKSZ_SHA1);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002536 *value_len = 20;
Stephen Warren6904b6e2011-10-18 11:11:49 +00002537 } else if (strcmp(algo, "md5") == 0) {
2538 md5_wd((unsigned char *)data, data_len, value, CHUNKSZ_MD5);
Bartlomiej Sieka2e6f2852008-03-14 16:22:34 +01002539 *value_len = 16;
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002540 } else {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002541 debug("Unsupported hash alogrithm\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002542 return -1;
2543 }
2544 return 0;
2545}
2546
2547#ifdef USE_HOSTCC
2548/**
2549 * fit_set_hashes - process FIT component image nodes and calculate hashes
2550 * @fit: pointer to the FIT format image header
2551 *
2552 * fit_set_hashes() adds hash values for all component images in the FIT blob.
2553 * Hashes are calculated for all component images which have hash subnodes
2554 * with algorithm property set to one of the supported hash algorithms.
2555 *
2556 * returns
2557 * 0, on success
2558 * libfdt error code, on failure
2559 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002560int fit_set_hashes(void *fit)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002561{
2562 int images_noffset;
2563 int noffset;
2564 int ndepth;
2565 int ret;
2566
2567 /* Find images parent node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002568 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002569 if (images_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002570 printf("Can't find images parent node '%s' (%s)\n",
2571 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002572 return images_noffset;
2573 }
2574
2575 /* Process its subnodes, print out component images details */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002576 for (ndepth = 0, noffset = fdt_next_node(fit, images_noffset, &ndepth);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002577 (noffset >= 0) && (ndepth > 0);
Stephen Warren6904b6e2011-10-18 11:11:49 +00002578 noffset = fdt_next_node(fit, noffset, &ndepth)) {
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002579 if (ndepth == 1) {
2580 /*
2581 * Direct child node of the images parent node,
2582 * i.e. component image node.
2583 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002584 ret = fit_image_set_hashes(fit, noffset);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002585 if (ret)
2586 return ret;
2587 }
2588 }
2589
2590 return 0;
2591}
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +01002592
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002593/**
2594 * fit_image_set_hashes - calculate/set hashes for given component image node
2595 * @fit: pointer to the FIT format image header
2596 * @image_noffset: requested component image node
2597 *
2598 * fit_image_set_hashes() adds hash values for an component image node. All
2599 * existing hash subnodes are checked, if algorithm property is set to one of
2600 * the supported hash algorithms, hash value is computed and corresponding
2601 * hash node property is set, for example:
2602 *
2603 * Input component image node structure:
2604 *
2605 * o image@1 (at image_noffset)
2606 * | - data = [binary data]
2607 * o hash@1
2608 * |- algo = "sha1"
2609 *
2610 * Output component image node structure:
2611 *
2612 * o image@1 (at image_noffset)
2613 * | - data = [binary data]
2614 * o hash@1
2615 * |- algo = "sha1"
2616 * |- value = sha1(data)
2617 *
2618 * returns:
2619 * 0 on sucess
2620 * <0 on failure
2621 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002622int fit_image_set_hashes(void *fit, int image_noffset)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002623{
2624 const void *data;
2625 size_t size;
2626 char *algo;
2627 uint8_t value[FIT_MAX_HASH_LEN];
2628 int value_len;
2629 int noffset;
2630 int ndepth;
2631
2632 /* Get image data and data length */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002633 if (fit_image_get_data(fit, image_noffset, &data, &size)) {
2634 printf("Can't get image data/size\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002635 return -1;
2636 }
2637
2638 /* Process all hash subnodes of the component image node */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002639 for (ndepth = 0, noffset = fdt_next_node(fit, image_noffset, &ndepth);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002640 (noffset >= 0) && (ndepth > 0);
Stephen Warren6904b6e2011-10-18 11:11:49 +00002641 noffset = fdt_next_node(fit, noffset, &ndepth)) {
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002642 if (ndepth == 1) {
2643 /* Direct child node of the component image node */
2644
2645 /*
2646 * Check subnode name, must be equal to "hash".
2647 * Multiple hash nodes require unique unit node
2648 * names, e.g. hash@1, hash@2, etc.
2649 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002650 if (strncmp(fit_get_name(fit, noffset, NULL),
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002651 FIT_HASH_NODENAME,
2652 strlen(FIT_HASH_NODENAME)) != 0) {
2653 /* Not a hash subnode, skip it */
2654 continue;
2655 }
2656
Stephen Warren6904b6e2011-10-18 11:11:49 +00002657 if (fit_image_hash_get_algo(fit, noffset, &algo)) {
2658 printf("Can't get hash algo property for "
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002659 "'%s' hash node in '%s' image node\n",
Stephen Warren6904b6e2011-10-18 11:11:49 +00002660 fit_get_name(fit, noffset, NULL),
2661 fit_get_name(fit, image_noffset, NULL));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002662 return -1;
2663 }
2664
Stephen Warren6904b6e2011-10-18 11:11:49 +00002665 if (calculate_hash(data, size, algo, value,
2666 &value_len)) {
2667 printf("Unsupported hash algorithm (%s) for "
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002668 "'%s' hash node in '%s' image node\n",
Stephen Warren6904b6e2011-10-18 11:11:49 +00002669 algo, fit_get_name(fit, noffset, NULL),
2670 fit_get_name(fit, image_noffset,
2671 NULL));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002672 return -1;
2673 }
2674
Stephen Warren6904b6e2011-10-18 11:11:49 +00002675 if (fit_image_hash_set_value(fit, noffset, value,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002676 value_len)) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002677 printf("Can't set hash value for "
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002678 "'%s' hash node in '%s' image node\n",
Stephen Warren6904b6e2011-10-18 11:11:49 +00002679 fit_get_name(fit, noffset, NULL),
2680 fit_get_name(fit, image_noffset, NULL));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002681 return -1;
2682 }
2683 }
2684 }
2685
2686 return 0;
2687}
2688
2689/**
2690 * fit_image_hash_set_value - set hash value in requested has node
2691 * @fit: pointer to the FIT format image header
2692 * @noffset: hash node offset
2693 * @value: hash value to be set
2694 * @value_len: hash value length
2695 *
2696 * fit_image_hash_set_value() attempts to set hash value in a node at offset
2697 * given and returns operation status to the caller.
2698 *
2699 * returns
2700 * 0, on success
2701 * -1, on failure
2702 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002703int fit_image_hash_set_value(void *fit, int noffset, uint8_t *value,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002704 int value_len)
2705{
2706 int ret;
2707
Stephen Warren6904b6e2011-10-18 11:11:49 +00002708 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002709 if (ret) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002710 printf("Can't set hash '%s' property for '%s' node(%s)\n",
2711 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
2712 fdt_strerror(ret));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002713 return -1;
2714 }
2715
2716 return 0;
2717}
2718#endif /* USE_HOSTCC */
2719
2720/**
2721 * fit_image_check_hashes - verify data intergity
2722 * @fit: pointer to the FIT format image header
2723 * @image_noffset: component image node offset
2724 *
2725 * fit_image_check_hashes() goes over component image hash nodes,
2726 * re-calculates each data hash and compares with the value stored in hash
2727 * node.
2728 *
2729 * returns:
2730 * 1, if all hashes are valid
2731 * 0, otherwise (or on error)
2732 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002733int fit_image_check_hashes(const void *fit, int image_noffset)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002734{
2735 const void *data;
2736 size_t size;
2737 char *algo;
2738 uint8_t *fit_value;
2739 int fit_value_len;
2740 uint8_t value[FIT_MAX_HASH_LEN];
2741 int value_len;
2742 int noffset;
2743 int ndepth;
2744 char *err_msg = "";
2745
2746 /* Get image data and data length */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002747 if (fit_image_get_data(fit, image_noffset, &data, &size)) {
2748 printf("Can't get image data/size\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002749 return 0;
2750 }
2751
2752 /* Process all hash subnodes of the component image node */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002753 for (ndepth = 0, noffset = fdt_next_node(fit, image_noffset, &ndepth);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002754 (noffset >= 0) && (ndepth > 0);
Stephen Warren6904b6e2011-10-18 11:11:49 +00002755 noffset = fdt_next_node(fit, noffset, &ndepth)) {
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002756 if (ndepth == 1) {
2757 /* Direct child node of the component image node */
2758
2759 /*
2760 * Check subnode name, must be equal to "hash".
2761 * Multiple hash nodes require unique unit node
2762 * names, e.g. hash@1, hash@2, etc.
2763 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002764 if (strncmp(fit_get_name(fit, noffset, NULL),
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002765 FIT_HASH_NODENAME,
2766 strlen(FIT_HASH_NODENAME)) != 0)
2767 continue;
2768
Stephen Warren6904b6e2011-10-18 11:11:49 +00002769 if (fit_image_hash_get_algo(fit, noffset, &algo)) {
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002770 err_msg = " error!\nCan't get hash algo "
2771 "property";
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002772 goto error;
2773 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00002774 printf("%s", algo);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002775
Stephen Warren6904b6e2011-10-18 11:11:49 +00002776 if (fit_image_hash_get_value(fit, noffset, &fit_value,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002777 &fit_value_len)) {
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002778 err_msg = " error!\nCan't get hash value "
2779 "property";
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002780 goto error;
2781 }
2782
Stephen Warren6904b6e2011-10-18 11:11:49 +00002783 if (calculate_hash(data, size, algo, value,
2784 &value_len)) {
2785 err_msg = " error!\n"
2786 "Unsupported hash algorithm";
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002787 goto error;
2788 }
2789
2790 if (value_len != fit_value_len) {
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002791 err_msg = " error !\nBad hash value len";
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002792 goto error;
Stephen Warren6904b6e2011-10-18 11:11:49 +00002793 } else if (memcmp(value, fit_value, value_len) != 0) {
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002794 err_msg = " error!\nBad hash value";
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002795 goto error;
2796 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00002797 printf("+ ");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002798 }
2799 }
2800
2801 return 1;
2802
2803error:
Stephen Warren6904b6e2011-10-18 11:11:49 +00002804 printf("%s for '%s' hash node in '%s' image node\n",
2805 err_msg, fit_get_name(fit, noffset, NULL),
2806 fit_get_name(fit, image_noffset, NULL));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002807 return 0;
2808}
2809
2810/**
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002811 * fit_all_image_check_hashes - verify data intergity for all images
2812 * @fit: pointer to the FIT format image header
2813 *
2814 * fit_all_image_check_hashes() goes over all images in the FIT and
2815 * for every images checks if all it's hashes are valid.
2816 *
2817 * returns:
2818 * 1, if all hashes of all images are valid
2819 * 0, otherwise (or on error)
2820 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002821int fit_all_image_check_hashes(const void *fit)
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002822{
2823 int images_noffset;
2824 int noffset;
2825 int ndepth;
2826 int count;
2827
2828 /* Find images parent node offset */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002829 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002830 if (images_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00002831 printf("Can't find images parent node '%s' (%s)\n",
2832 FIT_IMAGES_PATH, fdt_strerror(images_noffset));
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002833 return 0;
2834 }
2835
2836 /* Process all image subnodes, check hashes for each */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002837 printf("## Checking hash(es) for FIT Image at %08lx ...\n",
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002838 (ulong)fit);
2839 for (ndepth = 0, count = 0,
Stephen Warren6904b6e2011-10-18 11:11:49 +00002840 noffset = fdt_next_node(fit, images_noffset, &ndepth);
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002841 (noffset >= 0) && (ndepth > 0);
Stephen Warren6904b6e2011-10-18 11:11:49 +00002842 noffset = fdt_next_node(fit, noffset, &ndepth)) {
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002843 if (ndepth == 1) {
2844 /*
2845 * Direct child node of the images parent node,
2846 * i.e. component image node.
2847 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002848 printf(" Hash(es) for Image %u (%s): ", count++,
2849 fit_get_name(fit, noffset, NULL));
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002850
Stephen Warren6904b6e2011-10-18 11:11:49 +00002851 if (!fit_image_check_hashes(fit, noffset))
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002852 return 0;
Stephen Warren6904b6e2011-10-18 11:11:49 +00002853 printf("\n");
Bartlomiej Sieka1557a542008-09-09 12:58:15 +02002854 }
2855 }
2856 return 1;
2857}
2858
2859/**
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002860 * fit_image_check_os - check whether image node is of a given os type
2861 * @fit: pointer to the FIT format image header
2862 * @noffset: component image node offset
2863 * @os: requested image os
2864 *
2865 * fit_image_check_os() reads image os property and compares its numeric
2866 * id with the requested os. Comparison result is returned to the caller.
2867 *
2868 * returns:
2869 * 1 if image is of given os type
2870 * 0 otherwise (or on error)
2871 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002872int fit_image_check_os(const void *fit, int noffset, uint8_t os)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002873{
2874 uint8_t image_os;
2875
Stephen Warren6904b6e2011-10-18 11:11:49 +00002876 if (fit_image_get_os(fit, noffset, &image_os))
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002877 return 0;
2878 return (os == image_os);
2879}
2880
2881/**
2882 * fit_image_check_arch - check whether image node is of a given arch
2883 * @fit: pointer to the FIT format image header
2884 * @noffset: component image node offset
2885 * @arch: requested imagearch
2886 *
2887 * fit_image_check_arch() reads image arch property and compares its numeric
2888 * id with the requested arch. Comparison result is returned to the caller.
2889 *
2890 * returns:
2891 * 1 if image is of given arch
2892 * 0 otherwise (or on error)
2893 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002894int fit_image_check_arch(const void *fit, int noffset, uint8_t arch)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002895{
2896 uint8_t image_arch;
2897
Stephen Warren6904b6e2011-10-18 11:11:49 +00002898 if (fit_image_get_arch(fit, noffset, &image_arch))
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002899 return 0;
2900 return (arch == image_arch);
2901}
2902
2903/**
2904 * fit_image_check_type - check whether image node is of a given type
2905 * @fit: pointer to the FIT format image header
2906 * @noffset: component image node offset
2907 * @type: requested image type
2908 *
2909 * fit_image_check_type() reads image type property and compares its numeric
2910 * id with the requested type. Comparison result is returned to the caller.
2911 *
2912 * returns:
2913 * 1 if image is of given type
2914 * 0 otherwise (or on error)
2915 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002916int fit_image_check_type(const void *fit, int noffset, uint8_t type)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002917{
2918 uint8_t image_type;
2919
Stephen Warren6904b6e2011-10-18 11:11:49 +00002920 if (fit_image_get_type(fit, noffset, &image_type))
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002921 return 0;
2922 return (type == image_type);
2923}
2924
2925/**
2926 * fit_image_check_comp - check whether image node uses given compression
2927 * @fit: pointer to the FIT format image header
2928 * @noffset: component image node offset
2929 * @comp: requested image compression type
2930 *
2931 * fit_image_check_comp() reads image compression property and compares its
2932 * numeric id with the requested compression type. Comparison result is
2933 * returned to the caller.
2934 *
2935 * returns:
2936 * 1 if image uses requested compression
2937 * 0 otherwise (or on error)
2938 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002939int fit_image_check_comp(const void *fit, int noffset, uint8_t comp)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002940{
2941 uint8_t image_comp;
2942
Stephen Warren6904b6e2011-10-18 11:11:49 +00002943 if (fit_image_get_comp(fit, noffset, &image_comp))
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002944 return 0;
2945 return (comp == image_comp);
2946}
2947
2948/**
2949 * fit_check_format - sanity check FIT image format
2950 * @fit: pointer to the FIT format image header
2951 *
2952 * fit_check_format() runs a basic sanity FIT image verification.
2953 * Routine checks for mandatory properties, nodes, etc.
2954 *
2955 * returns:
2956 * 1, on success
2957 * 0, on failure
2958 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002959int fit_check_format(const void *fit)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002960{
2961 /* mandatory / node 'description' property */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002962 if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) {
2963 debug("Wrong FIT format: no description\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002964 return 0;
2965 }
2966
2967#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
2968 /* mandatory / node 'timestamp' property */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002969 if (fdt_getprop(fit, 0, FIT_TIMESTAMP_PROP, NULL) == NULL) {
2970 debug("Wrong FIT format: no timestamp\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002971 return 0;
2972 }
2973#endif
2974
2975 /* mandatory subimages parent '/images' node */
Stephen Warren6904b6e2011-10-18 11:11:49 +00002976 if (fdt_path_offset(fit, FIT_IMAGES_PATH) < 0) {
2977 debug("Wrong FIT format: no images parent node\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01002978 return 0;
2979 }
2980
2981 return 1;
2982}
2983
2984/**
2985 * fit_conf_get_node - get node offset for configuration of a given unit name
2986 * @fit: pointer to the FIT format image header
2987 * @conf_uname: configuration node unit name
2988 *
2989 * fit_conf_get_node() finds a configuration (withing the '/configurations'
2990 * parant node) of a provided unit name. If configuration is found its node offset
2991 * is returned to the caller.
2992 *
2993 * When NULL is provided in second argument fit_conf_get_node() will search
2994 * for a default configuration node instead. Default configuration node unit name
2995 * is retrived from FIT_DEFAULT_PROP property of the '/configurations' node.
2996 *
2997 * returns:
2998 * configuration node offset when found (>=0)
2999 * negative number on failure (FDT_ERR_* code)
3000 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003001int fit_conf_get_node(const void *fit, const char *conf_uname)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003002{
3003 int noffset, confs_noffset;
3004 int len;
3005
Stephen Warren6904b6e2011-10-18 11:11:49 +00003006 confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003007 if (confs_noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00003008 debug("Can't find configurations parent node '%s' (%s)\n",
3009 FIT_CONFS_PATH, fdt_strerror(confs_noffset));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003010 return confs_noffset;
3011 }
3012
3013 if (conf_uname == NULL) {
3014 /* get configuration unit name from the default property */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003015 debug("No configuration specified, trying default...\n");
3016 conf_uname = (char *)fdt_getprop(fit, confs_noffset,
3017 FIT_DEFAULT_PROP, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003018 if (conf_uname == NULL) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00003019 fit_get_debug(fit, confs_noffset, FIT_DEFAULT_PROP,
3020 len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003021 return len;
3022 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00003023 debug("Found default configuration: '%s'\n", conf_uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003024 }
3025
Stephen Warren6904b6e2011-10-18 11:11:49 +00003026 noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003027 if (noffset < 0) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00003028 debug("Can't get node offset for configuration unit name: "
3029 "'%s' (%s)\n",
3030 conf_uname, fdt_strerror(noffset));
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003031 }
3032
3033 return noffset;
3034}
3035
Stephen Warren6904b6e2011-10-18 11:11:49 +00003036static int __fit_conf_get_prop_node(const void *fit, int noffset,
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003037 const char *prop_name)
3038{
3039 char *uname;
3040 int len;
3041
3042 /* get kernel image unit name from configuration kernel property */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003043 uname = (char *)fdt_getprop(fit, noffset, prop_name, &len);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003044 if (uname == NULL)
3045 return len;
3046
Stephen Warren6904b6e2011-10-18 11:11:49 +00003047 return fit_image_get_node(fit, uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003048}
3049
3050/**
3051 * fit_conf_get_kernel_node - get kernel image node offset that corresponds to
3052 * a given configuration
3053 * @fit: pointer to the FIT format image header
3054 * @noffset: configuration node offset
3055 *
3056 * fit_conf_get_kernel_node() retrives kernel image node unit name from
3057 * configuration FIT_KERNEL_PROP property and translates it to the node
3058 * offset.
3059 *
3060 * returns:
3061 * image node offset when found (>=0)
3062 * negative number on failure (FDT_ERR_* code)
3063 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003064int fit_conf_get_kernel_node(const void *fit, int noffset)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003065{
Stephen Warren6904b6e2011-10-18 11:11:49 +00003066 return __fit_conf_get_prop_node(fit, noffset, FIT_KERNEL_PROP);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003067}
3068
3069/**
3070 * fit_conf_get_ramdisk_node - get ramdisk image node offset that corresponds to
3071 * a given configuration
3072 * @fit: pointer to the FIT format image header
3073 * @noffset: configuration node offset
3074 *
3075 * fit_conf_get_ramdisk_node() retrives ramdisk image node unit name from
3076 * configuration FIT_KERNEL_PROP property and translates it to the node
3077 * offset.
3078 *
3079 * returns:
3080 * image node offset when found (>=0)
3081 * negative number on failure (FDT_ERR_* code)
3082 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003083int fit_conf_get_ramdisk_node(const void *fit, int noffset)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003084{
Stephen Warren6904b6e2011-10-18 11:11:49 +00003085 return __fit_conf_get_prop_node(fit, noffset, FIT_RAMDISK_PROP);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003086}
3087
3088/**
3089 * fit_conf_get_fdt_node - get fdt image node offset that corresponds to
3090 * a given configuration
3091 * @fit: pointer to the FIT format image header
3092 * @noffset: configuration node offset
3093 *
3094 * fit_conf_get_fdt_node() retrives fdt image node unit name from
3095 * configuration FIT_KERNEL_PROP property and translates it to the node
3096 * offset.
3097 *
3098 * returns:
3099 * image node offset when found (>=0)
3100 * negative number on failure (FDT_ERR_* code)
3101 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003102int fit_conf_get_fdt_node(const void *fit, int noffset)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003103{
Stephen Warren6904b6e2011-10-18 11:11:49 +00003104 return __fit_conf_get_prop_node(fit, noffset, FIT_FDT_PROP);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003105}
3106
3107/**
3108 * fit_conf_print - prints out the FIT configuration details
3109 * @fit: pointer to the FIT format image header
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +01003110 * @noffset: offset of the configuration node
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003111 * @p: pointer to prefix string
3112 *
3113 * fit_conf_print() lists all mandatory properies for the processed
3114 * configuration node.
3115 *
3116 * returns:
3117 * no returned results
3118 */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003119void fit_conf_print(const void *fit, int noffset, const char *p)
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003120{
3121 char *desc;
3122 char *uname;
3123 int ret;
3124
3125 /* Mandatory properties */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003126 ret = fit_get_desc(fit, noffset, &desc);
3127 printf("%s Description: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003128 if (ret)
Stephen Warren6904b6e2011-10-18 11:11:49 +00003129 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003130 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00003131 printf("%s\n", desc);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003132
Stephen Warren6904b6e2011-10-18 11:11:49 +00003133 uname = (char *)fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL);
3134 printf("%s Kernel: ", p);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003135 if (uname == NULL)
Stephen Warren6904b6e2011-10-18 11:11:49 +00003136 printf("unavailable\n");
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003137 else
Stephen Warren6904b6e2011-10-18 11:11:49 +00003138 printf("%s\n", uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003139
3140 /* Optional properties */
Stephen Warren6904b6e2011-10-18 11:11:49 +00003141 uname = (char *)fdt_getprop(fit, noffset, FIT_RAMDISK_PROP, NULL);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003142 if (uname)
Stephen Warren6904b6e2011-10-18 11:11:49 +00003143 printf("%s Init Ramdisk: %s\n", p, uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003144
Stephen Warren6904b6e2011-10-18 11:11:49 +00003145 uname = (char *)fdt_getprop(fit, noffset, FIT_FDT_PROP, NULL);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003146 if (uname)
Stephen Warren6904b6e2011-10-18 11:11:49 +00003147 printf("%s FDT: %s\n", p, uname);
Marian Balakowicze227fbb2008-02-29 21:24:06 +01003148}
Marian Balakowicza50d5152008-03-12 10:12:37 +01003149
3150/**
3151 * fit_check_ramdisk - verify FIT format ramdisk subimage
3152 * @fit_hdr: pointer to the FIT ramdisk header
3153 * @rd_noffset: ramdisk subimage node offset within FIT image
3154 * @arch: requested ramdisk image architecture type
3155 * @verify: data CRC verification flag
3156 *
3157 * fit_check_ramdisk() verifies integrity of the ramdisk subimage and from
3158 * specified FIT image.
3159 *
3160 * returns:
3161 * 1, on success
3162 * 0, on failure
3163 */
3164#ifndef USE_HOSTCC
Stephen Warren6904b6e2011-10-18 11:11:49 +00003165static int fit_check_ramdisk(const void *fit, int rd_noffset, uint8_t arch,
3166 int verify)
Marian Balakowicza50d5152008-03-12 10:12:37 +01003167{
Stephen Warren6904b6e2011-10-18 11:11:49 +00003168 fit_image_print(fit, rd_noffset, " ");
Marian Balakowicza50d5152008-03-12 10:12:37 +01003169
3170 if (verify) {
Stephen Warren6904b6e2011-10-18 11:11:49 +00003171 puts(" Verifying Hash Integrity ... ");
3172 if (!fit_image_check_hashes(fit, rd_noffset)) {
3173 puts("Bad Data Hash\n");
3174 show_boot_progress(-125);
Marian Balakowicza50d5152008-03-12 10:12:37 +01003175 return 0;
3176 }
Stephen Warren6904b6e2011-10-18 11:11:49 +00003177 puts("OK\n");
Marian Balakowicza50d5152008-03-12 10:12:37 +01003178 }
3179
Stephen Warren6904b6e2011-10-18 11:11:49 +00003180 show_boot_progress(126);
3181 if (!fit_image_check_os(fit, rd_noffset, IH_OS_LINUX) ||
3182 !fit_image_check_arch(fit, rd_noffset, arch) ||
3183 !fit_image_check_type(fit, rd_noffset, IH_TYPE_RAMDISK)) {
3184 printf("No Linux %s Ramdisk Image\n",
Marian Balakowicza50d5152008-03-12 10:12:37 +01003185 genimg_get_arch_name(arch));
Stephen Warren6904b6e2011-10-18 11:11:49 +00003186 show_boot_progress(-126);
Marian Balakowicza50d5152008-03-12 10:12:37 +01003187 return 0;
3188 }
3189
Stephen Warren6904b6e2011-10-18 11:11:49 +00003190 show_boot_progress(127);
Marian Balakowicza50d5152008-03-12 10:12:37 +01003191 return 1;
3192}
3193#endif /* USE_HOSTCC */
Marian Balakowicz3413e222008-02-21 17:20:20 +01003194#endif /* CONFIG_FIT */