image.c 40.5 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2 3 4 5 6 7
/*
 * (C) Copyright 2008 Semihalf
 *
 * (C) Copyright 2000-2006
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 */
8

9
#ifndef USE_HOSTCC
10 11 12 13 14 15 16
#include <common.h>
#include <watchdog.h>

#ifdef CONFIG_SHOW_BOOT_PROGRESS
#include <status_led.h>
#endif

17 18
#include <rtc.h>

J
Joe Hershberger 已提交
19
#include <environment.h>
20
#include <image.h>
21
#include <mapmem.h>
22

23
#if IMAGE_ENABLE_FIT || IMAGE_ENABLE_OF_LIBFDT
24
#include <linux/libfdt.h>
25
#include <fdt_support.h>
26 27
#include <fpga.h>
#include <xilinx.h>
28 29
#endif

30
#include <u-boot/md5.h>
31
#include <u-boot/sha1.h>
32
#include <linux/errno.h>
33
#include <asm/io.h>
34

35
#ifdef CONFIG_CMD_BDI
36
extern int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
37 38 39
#endif

DECLARE_GLOBAL_DATA_PTR;
40

41
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
S
Stephen Warren 已提交
42
static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
43
						int verify);
44
#endif
45
#else
46
#include "mkimage.h"
47
#include <u-boot/md5.h>
48
#include <time.h>
49
#include <image.h>
50 51 52 53

#ifndef __maybe_unused
# define __maybe_unused		/* unimplemented */
#endif
54
#endif /* !USE_HOSTCC*/
55

56 57
#include <u-boot/crc.h>

58 59 60 61
#ifndef CONFIG_SYS_BARGSIZE
#define CONFIG_SYS_BARGSIZE 512
#endif

M
Mike Frysinger 已提交
62
static const table_entry_t uimage_arch[] = {
63
	{	IH_ARCH_INVALID,	"invalid",	"Invalid ARCH",	},
64 65 66 67 68 69 70 71 72
	{	IH_ARCH_ALPHA,		"alpha",	"Alpha",	},
	{	IH_ARCH_ARM,		"arm",		"ARM",		},
	{	IH_ARCH_I386,		"x86",		"Intel x86",	},
	{	IH_ARCH_IA64,		"ia64",		"IA64",		},
	{	IH_ARCH_M68K,		"m68k",		"M68K",		},
	{	IH_ARCH_MICROBLAZE,	"microblaze",	"MicroBlaze",	},
	{	IH_ARCH_MIPS,		"mips",		"MIPS",		},
	{	IH_ARCH_MIPS64,		"mips64",	"MIPS 64 Bit",	},
	{	IH_ARCH_NIOS2,		"nios2",	"NIOS II",	},
73
	{	IH_ARCH_PPC,		"powerpc",	"PowerPC",	},
74 75 76 77 78 79 80
	{	IH_ARCH_PPC,		"ppc",		"PowerPC",	},
	{	IH_ARCH_S390,		"s390",		"IBM S390",	},
	{	IH_ARCH_SH,		"sh",		"SuperH",	},
	{	IH_ARCH_SPARC,		"sparc",	"SPARC",	},
	{	IH_ARCH_SPARC64,	"sparc64",	"SPARC 64 Bit",	},
	{	IH_ARCH_BLACKFIN,	"blackfin",	"Blackfin",	},
	{	IH_ARCH_AVR32,		"avr32",	"AVR32",	},
81
	{	IH_ARCH_NDS32,		"nds32",	"NDS32",	},
82
	{	IH_ARCH_OPENRISC,	"or1k",		"OpenRISC 1000",},
83
	{	IH_ARCH_SANDBOX,	"sandbox",	"Sandbox",	},
D
David Feng 已提交
84
	{	IH_ARCH_ARM64,		"arm64",	"AArch64",	},
85
	{	IH_ARCH_ARC,		"arc",		"ARC",		},
86
	{	IH_ARCH_X86_64,		"x86_64",	"AMD x86_64",	},
87
	{	IH_ARCH_XTENSA,		"xtensa",	"Xtensa",	},
R
Rick Chen 已提交
88
	{	IH_ARCH_RISCV,		"riscv",	"RISC-V",	},
89 90 91
	{	-1,			"",		"",		},
};

M
Mike Frysinger 已提交
92
static const table_entry_t uimage_os[] = {
93
	{	IH_OS_INVALID,	"invalid",	"Invalid OS",		},
94
	{       IH_OS_ARM_TRUSTED_FIRMWARE, "arm-trusted-firmware", "ARM Trusted Firmware"  },
95 96 97 98 99
	{	IH_OS_LINUX,	"linux",	"Linux",		},
#if defined(CONFIG_LYNXKDI) || defined(USE_HOSTCC)
	{	IH_OS_LYNXOS,	"lynxos",	"LynxOS",		},
#endif
	{	IH_OS_NETBSD,	"netbsd",	"NetBSD",		},
100
	{	IH_OS_OSE,	"ose",		"Enea OSE",		},
S
Steven Stallion 已提交
101
	{	IH_OS_PLAN9,	"plan9",	"Plan 9",		},
102
	{	IH_OS_RTEMS,	"rtems",	"RTEMS",		},
103
	{	IH_OS_TEE,	"tee",		"Trusted Execution Environment" },
104
	{	IH_OS_U_BOOT,	"u-boot",	"U-Boot",		},
105
	{	IH_OS_VXWORKS,	"vxworks",	"VxWorks",		},
106 107 108
#if defined(CONFIG_CMD_ELF) || defined(USE_HOSTCC)
	{	IH_OS_QNX,	"qnx",		"QNX",			},
#endif
109 110 111
#if defined(CONFIG_INTEGRITY) || defined(USE_HOSTCC)
	{	IH_OS_INTEGRITY,"integrity",	"INTEGRITY",		},
#endif
112 113 114 115 116 117 118 119 120 121 122 123 124
#ifdef USE_HOSTCC
	{	IH_OS_4_4BSD,	"4_4bsd",	"4_4BSD",		},
	{	IH_OS_DELL,	"dell",		"Dell",			},
	{	IH_OS_ESIX,	"esix",		"Esix",			},
	{	IH_OS_FREEBSD,	"freebsd",	"FreeBSD",		},
	{	IH_OS_IRIX,	"irix",		"Irix",			},
	{	IH_OS_NCR,	"ncr",		"NCR",			},
	{	IH_OS_OPENBSD,	"openbsd",	"OpenBSD",		},
	{	IH_OS_PSOS,	"psos",		"pSOS",			},
	{	IH_OS_SCO,	"sco",		"SCO",			},
	{	IH_OS_SOLARIS,	"solaris",	"Solaris",		},
	{	IH_OS_SVR4,	"svr4",		"SVR4",			},
#endif
125 126 127 128
#if defined(CONFIG_BOOTM_OPENRTOS) || defined(USE_HOSTCC)
	{	IH_OS_OPENRTOS,	"openrtos",	"OpenRTOS",		},
#endif

129 130 131
	{	-1,		"",		"",			},
};

M
Mike Frysinger 已提交
132
static const table_entry_t uimage_type[] = {
133
	{	IH_TYPE_AISIMAGE,   "aisimage",   "Davinci AIS image",},
134 135
	{	IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image",	},
	{	IH_TYPE_FIRMWARE,   "firmware",	  "Firmware",		},
136
	{	IH_TYPE_FLATDT,     "flat_dt",    "Flat Device Tree",	},
137
	{	IH_TYPE_GPIMAGE,    "gpimage",    "TI Keystone SPL Image",},
138
	{	IH_TYPE_KERNEL,	    "kernel",	  "Kernel Image",	},
139
	{	IH_TYPE_KERNEL_NOLOAD, "kernel_noload",  "Kernel Image (no loading done)", },
140 141
	{	IH_TYPE_KWBIMAGE,   "kwbimage",   "Kirkwood Boot Image",},
	{	IH_TYPE_IMXIMAGE,   "imximage",   "Freescale i.MX Boot Image",},
P
Peng Fan 已提交
142
	{	IH_TYPE_IMX8IMAGE,  "imx8image",  "NXP i.MX8 Boot Image",},
143
	{	IH_TYPE_INVALID,    "invalid",	  "Invalid Image",	},
144
	{	IH_TYPE_MULTI,	    "multi",	  "Multi-File Image",	},
145
	{	IH_TYPE_OMAPIMAGE,  "omapimage",  "TI OMAP SPL With GP CH",},
146
	{	IH_TYPE_PBLIMAGE,   "pblimage",   "Freescale PBL Boot Image",},
147 148
	{	IH_TYPE_RAMDISK,    "ramdisk",	  "RAMDisk Image",	},
	{	IH_TYPE_SCRIPT,     "script",	  "Script",		},
149 150
	{	IH_TYPE_SOCFPGAIMAGE, "socfpgaimage", "Altera SoCFPGA CV/AV preloader",},
	{	IH_TYPE_SOCFPGAIMAGE_V1, "socfpgaimage_v1", "Altera SoCFPGA A10 preloader",},
151
	{	IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
152
	{	IH_TYPE_UBLIMAGE,   "ublimage",   "Davinci UBL image",},
153
	{	IH_TYPE_MXSIMAGE,   "mxsimage",   "Freescale MXS Boot Image",},
A
Andreas Bießmann 已提交
154
	{	IH_TYPE_ATMELIMAGE, "atmelimage", "ATMEL ROM-Boot Image",},
155
	{	IH_TYPE_X86_SETUP,  "x86_setup",  "x86 setup.bin",    },
156
	{	IH_TYPE_LPC32XXIMAGE, "lpc32xximage",  "LPC32XX Boot Image", },
157
	{	IH_TYPE_RKIMAGE,    "rkimage",    "Rockchip Boot Image" },
158
	{	IH_TYPE_RKSD,       "rksd",       "Rockchip SD Boot Image" },
159
	{	IH_TYPE_RKSPI,      "rkspi",      "Rockchip SPI Boot Image" },
160
	{	IH_TYPE_VYBRIDIMAGE, "vybridimage",  "Vybrid Boot Image", },
161
	{	IH_TYPE_ZYNQIMAGE,  "zynqimage",  "Xilinx Zynq Boot Image" },
162
	{	IH_TYPE_ZYNQMPIMAGE, "zynqmpimage", "Xilinx ZynqMP Boot Image" },
163
	{	IH_TYPE_ZYNQMPBIF,  "zynqmpbif",  "Xilinx ZynqMP Boot Image (bif)" },
164
	{	IH_TYPE_FPGA,       "fpga",       "FPGA Image" },
165
	{       IH_TYPE_TEE,        "tee",        "Trusted Execution Environment Image",},
166
	{	IH_TYPE_FIRMWARE_IVT, "firmware_ivt", "Firmware with HABv4 IVT" },
A
Andrew F. Davis 已提交
167
	{       IH_TYPE_PMMC,        "pmmc",        "TI Power Management Micro-Controller Firmware",},
168
	{	IH_TYPE_STM32IMAGE, "stm32image", "STMicroelectronics STM32 Image" },
169
	{	IH_TYPE_MTKIMAGE,   "mtk_image",   "MediaTek BootROM loadable Image" },
170 171 172
	{	-1,		    "",		  "",			},
};

M
Mike Frysinger 已提交
173
static const table_entry_t uimage_comp[] = {
174 175 176
	{	IH_COMP_NONE,	"none",		"uncompressed",		},
	{	IH_COMP_BZIP2,	"bzip2",	"bzip2 compressed",	},
	{	IH_COMP_GZIP,	"gzip",		"gzip compressed",	},
177
	{	IH_COMP_LZMA,	"lzma",		"lzma compressed",	},
P
Peter Korsgaard 已提交
178
	{	IH_COMP_LZO,	"lzo",		"lzo compressed",	},
179
	{	IH_COMP_LZ4,	"lz4",		"lz4 compressed",	},
180 181 182
	{	-1,		"",		"",			},
};

183 184 185 186 187 188 189 190 191 192 193 194 195
struct table_info {
	const char *desc;
	int count;
	const table_entry_t *table;
};

static const struct table_info table_info[IH_COUNT] = {
	{ "architecture", IH_ARCH_COUNT, uimage_arch },
	{ "compression", IH_COMP_COUNT, uimage_comp },
	{ "operating system", IH_OS_COUNT, uimage_os },
	{ "image type", IH_TYPE_COUNT, uimage_type },
};

196 197 198
/*****************************************************************************/
/* Legacy format routines */
/*****************************************************************************/
S
Stephen Warren 已提交
199
int image_check_hcrc(const image_header_t *hdr)
200 201
{
	ulong hcrc;
S
Stephen Warren 已提交
202
	ulong len = image_get_header_size();
203 204 205
	image_header_t header;

	/* Copy header so we can blank CRC field for re-calculation */
S
Stephen Warren 已提交
206 207
	memmove(&header, (char *)hdr, image_get_header_size());
	image_set_hcrc(&header, 0);
208

S
Stephen Warren 已提交
209
	hcrc = crc32(0, (unsigned char *)&header, len);
210

S
Stephen Warren 已提交
211
	return (hcrc == image_get_hcrc(hdr));
212 213
}

S
Stephen Warren 已提交
214
int image_check_dcrc(const image_header_t *hdr)
215
{
S
Stephen Warren 已提交
216 217 218
	ulong data = image_get_data(hdr);
	ulong len = image_get_data_size(hdr);
	ulong dcrc = crc32_wd(0, (unsigned char *)data, len, CHUNKSZ_CRC32);
219

S
Stephen Warren 已提交
220
	return (dcrc == image_get_dcrc(hdr));
221 222
}

223 224 225 226 227 228 229 230 231 232 233 234 235
/**
 * image_multi_count - get component (sub-image) count
 * @hdr: pointer to the header of the multi component image
 *
 * image_multi_count() returns number of components in a multi
 * component image.
 *
 * Note: no checking of the image type is done, caller must pass
 * a valid multi component image.
 *
 * returns:
 *     number of components
 */
S
Stephen Warren 已提交
236
ulong image_multi_count(const image_header_t *hdr)
237 238
{
	ulong i, count = 0;
239
	uint32_t *size;
240 241 242

	/* get start of the image payload, which in case of multi
	 * component images that points to a table of component sizes */
S
Stephen Warren 已提交
243
	size = (uint32_t *)image_get_data(hdr);
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

	/* count non empty slots */
	for (i = 0; size[i]; ++i)
		count++;

	return count;
}

/**
 * image_multi_getimg - get component data address and size
 * @hdr: pointer to the header of the multi component image
 * @idx: index of the requested component
 * @data: pointer to a ulong variable, will hold component data address
 * @len: pointer to a ulong variable, will hold component size
 *
 * image_multi_getimg() returns size and data address for the requested
 * component in a multi component image.
 *
 * Note: no checking of the image type is done, caller must pass
 * a valid multi component image.
 *
 * returns:
 *     data address and size of the component, if idx is valid
 *     0 in data and len, if idx is out of range
 */
S
Stephen Warren 已提交
269
void image_multi_getimg(const image_header_t *hdr, ulong idx,
270 271 272
			ulong *data, ulong *len)
{
	int i;
273
	uint32_t *size;
274
	ulong offset, count, img_data;
275 276

	/* get number of component */
S
Stephen Warren 已提交
277
	count = image_multi_count(hdr);
278 279 280

	/* get start of the image payload, which in case of multi
	 * component images that points to a table of component sizes */
S
Stephen Warren 已提交
281
	size = (uint32_t *)image_get_data(hdr);
282 283 284

	/* get address of the proper component data start, which means
	 * skipping sizes table (add 1 for last, null entry) */
S
Stephen Warren 已提交
285
	img_data = image_get_data(hdr) + (count + 1) * sizeof(uint32_t);
286 287

	if (idx < count) {
S
Stephen Warren 已提交
288
		*len = uimage_to_cpu(size[idx]);
289 290 291 292
		offset = 0;

		/* go over all indices preceding requested component idx */
		for (i = 0; i < idx; i++) {
293
			/* add up i-th component size, rounding up to 4 bytes */
S
Stephen Warren 已提交
294
			offset += (uimage_to_cpu(size[i]) + 3) & ~3 ;
295 296 297
		}

		/* calculate idx-th component data address */
298
		*data = img_data + offset;
299 300 301 302 303
	} else {
		*len = 0;
		*data = 0;
	}
}
304

S
Stephen Warren 已提交
305
static void image_print_type(const image_header_t *hdr)
306
{
307
	const char __maybe_unused *os, *arch, *type, *comp;
308

S
Stephen Warren 已提交
309 310 311 312
	os = genimg_get_os_name(image_get_os(hdr));
	arch = genimg_get_arch_name(image_get_arch(hdr));
	type = genimg_get_type_name(image_get_type(hdr));
	comp = genimg_get_comp_name(image_get_comp(hdr));
313

S
Stephen Warren 已提交
314
	printf("%s %s %s (%s)\n", arch, os, type, comp);
315 316
}

317
/**
318
 * image_print_contents - prints out the contents of the legacy format image
319
 * @ptr: pointer to the legacy format image header
320 321
 * @p: pointer to prefix string
 *
322
 * image_print_contents() formats a multi line legacy image contents description.
323 324 325 326 327 328
 * The routine prints out all header fields followed by the size/offset data
 * for MULTI/SCRIPT images.
 *
 * returns:
 *     no returned results
 */
S
Stephen Warren 已提交
329
void image_print_contents(const void *ptr)
330
{
331
	const image_header_t *hdr = (const image_header_t *)ptr;
332
	const char __maybe_unused *p;
333

334
	p = IMAGE_INDENT_STRING;
S
Stephen Warren 已提交
335
	printf("%sImage Name:   %.*s\n", p, IH_NMLEN, image_get_name(hdr));
336 337 338 339
	if (IMAGE_ENABLE_TIMESTAMP) {
		printf("%sCreated:      ", p);
		genimg_print_time((time_t)image_get_time(hdr));
	}
S
Stephen Warren 已提交
340 341 342 343 344 345 346 347 348
	printf("%sImage Type:   ", p);
	image_print_type(hdr);
	printf("%sData Size:    ", p);
	genimg_print_size(image_get_data_size(hdr));
	printf("%sLoad Address: %08x\n", p, image_get_load(hdr));
	printf("%sEntry Point:  %08x\n", p, image_get_ep(hdr));

	if (image_check_type(hdr, IH_TYPE_MULTI) ||
			image_check_type(hdr, IH_TYPE_SCRIPT)) {
349 350
		int i;
		ulong data, len;
S
Stephen Warren 已提交
351
		ulong count = image_multi_count(hdr);
352

S
Stephen Warren 已提交
353
		printf("%sContents:\n", p);
354
		for (i = 0; i < count; i++) {
S
Stephen Warren 已提交
355
			image_multi_getimg(hdr, i, &data, &len);
356

S
Stephen Warren 已提交
357 358
			printf("%s   Image %d: ", p, i);
			genimg_print_size(len);
359

S
Stephen Warren 已提交
360
			if (image_check_type(hdr, IH_TYPE_SCRIPT) && i > 0) {
361 362 363 364 365
				/*
				 * the user may need to know offsets
				 * if planning to do something with
				 * multiple files
				 */
S
Stephen Warren 已提交
366
				printf("%s    Offset = 0x%08lx\n", p, data);
367
			}
368
		}
369 370 371 372 373
	} else if (image_check_type(hdr, IH_TYPE_FIRMWARE_IVT)) {
		printf("HAB Blocks:   0x%08x   0x0000   0x%08x\n",
				image_get_load(hdr) - image_get_header_size(),
				image_get_size(hdr) + image_get_header_size()
						- 0x1FE0);
374 375 376
	}
}

377 378

#ifndef USE_HOSTCC
379
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
/**
 * image_get_ramdisk - get and verify ramdisk image
 * @rd_addr: ramdisk image start address
 * @arch: expected ramdisk architecture
 * @verify: checksum verification flag
 *
 * image_get_ramdisk() returns a pointer to the verified ramdisk image
 * header. Routine receives image start address and expected architecture
 * flag. Verification done covers data and header integrity and os/type/arch
 * fields checking.
 *
 * returns:
 *     pointer to a ramdisk image header, if image was found and valid
 *     otherwise, return NULL
 */
S
Stephen Warren 已提交
395
static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
396
						int verify)
397
{
398
	const image_header_t *rd_hdr = (const image_header_t *)rd_addr;
399

S
Stephen Warren 已提交
400 401
	if (!image_check_magic(rd_hdr)) {
		puts("Bad Magic Number\n");
402
		bootstage_error(BOOTSTAGE_ID_RD_MAGIC);
403 404 405
		return NULL;
	}

S
Stephen Warren 已提交
406 407
	if (!image_check_hcrc(rd_hdr)) {
		puts("Bad Header Checksum\n");
408
		bootstage_error(BOOTSTAGE_ID_RD_HDR_CHECKSUM);
409 410 411
		return NULL;
	}

412
	bootstage_mark(BOOTSTAGE_ID_RD_MAGIC);
S
Stephen Warren 已提交
413
	image_print_contents(rd_hdr);
414 415 416

	if (verify) {
		puts("   Verifying Checksum ... ");
S
Stephen Warren 已提交
417 418
		if (!image_check_dcrc(rd_hdr)) {
			puts("Bad Data CRC\n");
419
			bootstage_error(BOOTSTAGE_ID_RD_CHECKSUM);
420 421 422 423 424
			return NULL;
		}
		puts("OK\n");
	}

425
	bootstage_mark(BOOTSTAGE_ID_RD_HDR_CHECKSUM);
426

S
Stephen Warren 已提交
427 428 429 430
	if (!image_check_os(rd_hdr, IH_OS_LINUX) ||
	    !image_check_arch(rd_hdr, arch) ||
	    !image_check_type(rd_hdr, IH_TYPE_RAMDISK)) {
		printf("No Linux %s Ramdisk Image\n",
431
				genimg_get_arch_name(arch));
432
		bootstage_error(BOOTSTAGE_ID_RAMDISK);
433 434 435 436 437
		return NULL;
	}

	return rd_hdr;
}
438
#endif
439
#endif /* !USE_HOSTCC */
440 441 442 443

/*****************************************************************************/
/* Shared dual-format routines */
/*****************************************************************************/
444
#ifndef USE_HOSTCC
J
Joe Hershberger 已提交
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
ulong save_addr;			/* Default Save Address */
ulong save_size;			/* Default Save Size (in bytes) */

static int on_loadaddr(const char *name, const char *value, enum env_op op,
	int flags)
{
	switch (op) {
	case env_op_create:
	case env_op_overwrite:
		load_addr = simple_strtoul(value, NULL, 16);
		break;
	default:
		break;
	}

	return 0;
}
U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);

465
ulong env_get_bootm_low(void)
466
{
467
	char *s = env_get("bootm_low");
468
	if (s) {
S
Stephen Warren 已提交
469
		ulong tmp = simple_strtoul(s, NULL, 16);
470 471 472
		return tmp;
	}

473 474
#if defined(CONFIG_SYS_SDRAM_BASE)
	return CONFIG_SYS_SDRAM_BASE;
475 476
#elif defined(CONFIG_ARM)
	return gd->bd->bi_dram[0].start;
477 478 479 480 481
#else
	return 0;
#endif
}

482
phys_size_t env_get_bootm_size(void)
483
{
484 485
	phys_size_t tmp, size;
	phys_addr_t start;
486
	char *s = env_get("bootm_size");
487
	if (s) {
S
Stephen Warren 已提交
488
		tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
489 490
		return tmp;
	}
491 492 493 494 495 496 497 498 499

#if defined(CONFIG_ARM) && defined(CONFIG_NR_DRAM_BANKS)
	start = gd->bd->bi_dram[0].start;
	size = gd->bd->bi_dram[0].size;
#else
	start = gd->bd->bi_memstart;
	size = gd->bd->bi_memsize;
#endif

500
	s = env_get("bootm_low");
501
	if (s)
S
Stephen Warren 已提交
502
		tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
503
	else
504
		tmp = start;
505

506
	return size - (tmp - start);
507 508
}

509
phys_size_t env_get_bootm_mapsize(void)
510 511
{
	phys_size_t tmp;
512
	char *s = env_get("bootm_mapsize");
513
	if (s) {
S
Stephen Warren 已提交
514
		tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
515 516 517 518 519 520
		return tmp;
	}

#if defined(CONFIG_SYS_BOOTMAPSZ)
	return CONFIG_SYS_BOOTMAPSZ;
#else
521
	return env_get_bootm_size();
522 523 524
#endif
}

S
Stephen Warren 已提交
525
void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
526
{
527 528 529
	if (to == from)
		return;

530
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
531 532 533 534
	if (to > from) {
		from += len;
		to += len;
	}
535 536
	while (len > 0) {
		size_t tail = (len > chunksz) ? chunksz : len;
S
Stephen Warren 已提交
537
		WATCHDOG_RESET();
538 539 540 541
		if (to > from) {
			to -= tail;
			from -= tail;
		}
S
Stephen Warren 已提交
542
		memmove(to, from, tail);
543 544 545 546
		if (to < from) {
			to += tail;
			from += tail;
		}
547 548 549
		len -= tail;
	}
#else	/* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
S
Stephen Warren 已提交
550
	memmove(to, from, len);
551 552
#endif	/* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
}
553
#endif /* !USE_HOSTCC */
554

S
Stephen Warren 已提交
555
void genimg_print_size(uint32_t size)
556
{
557
#ifndef USE_HOSTCC
S
Stephen Warren 已提交
558 559
	printf("%d Bytes = ", size);
	print_size(size, "\n");
560
#else
561
	printf("%d Bytes = %.2f KiB = %.2f MiB\n",
562 563
			size, (double)size / 1.024e3,
			(double)size / 1.048576e6);
564
#endif
565 566
}

567 568
#if IMAGE_ENABLE_TIMESTAMP
void genimg_print_time(time_t timestamp)
569 570 571 572
{
#ifndef USE_HOSTCC
	struct rtc_time tm;

573
	rtc_to_tm(timestamp, &tm);
S
Stephen Warren 已提交
574
	printf("%4d-%02d-%02d  %2d:%02d:%02d UTC\n",
575 576 577
			tm.tm_year, tm.tm_mon, tm.tm_mday,
			tm.tm_hour, tm.tm_min, tm.tm_sec);
#else
S
Stephen Warren 已提交
578
	printf("%s", ctime(&timestamp));
579
#endif
580
}
581
#endif
582

583 584 585 586 587 588 589 590 591
const table_entry_t *get_table_entry(const table_entry_t *table, int id)
{
	for (; table->id >= 0; ++table) {
		if (table->id == id)
			return table;
	}
	return NULL;
}

592 593
static const char *unknown_msg(enum ih_category category)
{
594
	static const char unknown_str[] = "Unknown ";
595 596
	static char msg[30];

597 598 599
	strcpy(msg, unknown_str);
	strncat(msg, table_info[category].desc,
		sizeof(msg) - sizeof(unknown_str));
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661

	return msg;
}

/**
 * get_cat_table_entry_name - translate entry id to long name
 * @category: category to look up (enum ih_category)
 * @id: entry id to be translated
 *
 * This will scan the translation table trying to find the entry that matches
 * the given id.
 *
 * @retur long entry name if translation succeeds; error string on failure
 */
const char *genimg_get_cat_name(enum ih_category category, uint id)
{
	const table_entry_t *entry;

	entry = get_table_entry(table_info[category].table, id);
	if (!entry)
		return unknown_msg(category);
#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
	return entry->lname;
#else
	return entry->lname + gd->reloc_off;
#endif
}

/**
 * get_cat_table_entry_short_name - translate entry id to short name
 * @category: category to look up (enum ih_category)
 * @id: entry id to be translated
 *
 * This will scan the translation table trying to find the entry that matches
 * the given id.
 *
 * @retur short entry name if translation succeeds; error string on failure
 */
const char *genimg_get_cat_short_name(enum ih_category category, uint id)
{
	const table_entry_t *entry;

	entry = get_table_entry(table_info[category].table, id);
	if (!entry)
		return unknown_msg(category);
#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
	return entry->sname;
#else
	return entry->sname + gd->reloc_off;
#endif
}

int genimg_get_cat_count(enum ih_category category)
{
	return table_info[category].count;
}

const char *genimg_get_cat_desc(enum ih_category category)
{
	return table_info[category].desc;
}

662 663 664 665 666 667 668 669 670 671 672 673 674 675
/**
 * get_table_entry_name - translate entry id to long name
 * @table: pointer to a translation table for entries of a specific type
 * @msg: message to be returned when translation fails
 * @id: entry id to be translated
 *
 * get_table_entry_name() will go over translation table trying to find
 * entry that matches given id. If matching entry is found, its long
 * name is returned to the caller.
 *
 * returns:
 *     long entry name if translation succeeds
 *     msg otherwise
 */
M
Mike Frysinger 已提交
676
char *get_table_entry_name(const table_entry_t *table, char *msg, int id)
677
{
678 679 680
	table = get_table_entry(table, id);
	if (!table)
		return msg;
681
#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
682
	return table->lname;
683
#else
684
	return table->lname + gd->reloc_off;
685
#endif
686
}
687

S
Stephen Warren 已提交
688
const char *genimg_get_os_name(uint8_t os)
689
{
S
Stephen Warren 已提交
690
	return (get_table_entry_name(uimage_os, "Unknown OS", os));
691 692
}

S
Stephen Warren 已提交
693
const char *genimg_get_arch_name(uint8_t arch)
694
{
S
Stephen Warren 已提交
695 696
	return (get_table_entry_name(uimage_arch, "Unknown Architecture",
					arch));
697
}
698

S
Stephen Warren 已提交
699
const char *genimg_get_type_name(uint8_t type)
700
{
S
Stephen Warren 已提交
701
	return (get_table_entry_name(uimage_type, "Unknown Image", type));
702
}
703

704
static const char *genimg_get_short_name(const table_entry_t *table, int val)
705
{
706
	table = get_table_entry(table, val);
707 708 709 710 711 712 713 714 715
	if (!table)
		return "unknown";
#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
	return table->sname;
#else
	return table->sname + gd->reloc_off;
#endif
}

716 717 718 719 720
const char *genimg_get_type_short_name(uint8_t type)
{
	return genimg_get_short_name(uimage_type, type);
}

S
Stephen Warren 已提交
721
const char *genimg_get_comp_name(uint8_t comp)
722
{
S
Stephen Warren 已提交
723 724
	return (get_table_entry_name(uimage_comp, "Unknown Compression",
					comp));
725 726
}

727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
const char *genimg_get_comp_short_name(uint8_t comp)
{
	return genimg_get_short_name(uimage_comp, comp);
}

const char *genimg_get_os_short_name(uint8_t os)
{
	return genimg_get_short_name(uimage_os, os);
}

const char *genimg_get_arch_short_name(uint8_t arch)
{
	return genimg_get_short_name(uimage_arch, arch);
}

742 743 744 745 746 747 748 749 750 751 752 753 754 755
/**
 * get_table_entry_id - translate short entry name to id
 * @table: pointer to a translation table for entries of a specific type
 * @table_name: to be used in case of error
 * @name: entry short name to be translated
 *
 * get_table_entry_id() will go over translation table trying to find
 * entry that matches given short name. If matching entry is found,
 * its id returned to the caller.
 *
 * returns:
 *     entry id if translation succeeds
 *     -1 otherwise
 */
M
Mike Frysinger 已提交
756
int get_table_entry_id(const table_entry_t *table,
757
		const char *table_name, const char *name)
758
{
M
Mike Frysinger 已提交
759
	const table_entry_t *t;
760

761
	for (t = table; t->id >= 0; ++t) {
762
#ifdef CONFIG_NEEDS_MANUAL_RELOC
763
		if (t->sname && strcasecmp(t->sname + gd->reloc_off, name) == 0)
764
#else
765
		if (t->sname && strcasecmp(t->sname, name) == 0)
766
#endif
767 768
			return (t->id);
	}
S
Stephen Warren 已提交
769
	debug("Invalid %s Type: %s\n", table_name, name);
770 771

	return -1;
772 773
}

S
Stephen Warren 已提交
774
int genimg_get_os_id(const char *name)
775
{
S
Stephen Warren 已提交
776
	return (get_table_entry_id(uimage_os, "OS", name));
777 778
}

S
Stephen Warren 已提交
779
int genimg_get_arch_id(const char *name)
780
{
S
Stephen Warren 已提交
781
	return (get_table_entry_id(uimage_arch, "CPU", name));
782
}
783

S
Stephen Warren 已提交
784
int genimg_get_type_id(const char *name)
785
{
S
Stephen Warren 已提交
786
	return (get_table_entry_id(uimage_type, "Image", name));
787 788
}

S
Stephen Warren 已提交
789
int genimg_get_comp_id(const char *name)
790
{
S
Stephen Warren 已提交
791
	return (get_table_entry_id(uimage_comp, "Compression", name));
792 793 794
}

#ifndef USE_HOSTCC
795
/**
796 797
 * genimg_get_kernel_addr_fit - get the real kernel address and return 2
 *                              FIT strings
798
 * @img_addr: a string might contain real image address
799 800 801 802
 * @fit_uname_config: double pointer to a char, will hold pointer to a
 *                    configuration unit name
 * @fit_uname_kernel: double pointer to a char, will hold pointer to a subimage
 *                    name
803
 *
804
 * genimg_get_kernel_addr_fit get the real kernel start address from a string
805 806 807 808 809
 * which is normally the first argv of bootm/bootz
 *
 * returns:
 *     kernel start address
 */
810 811 812
ulong genimg_get_kernel_addr_fit(char * const img_addr,
			     const char **fit_uname_config,
			     const char **fit_uname_kernel)
813 814 815 816 817 818 819 820
{
	ulong kernel_addr;

	/* find out kernel image address */
	if (!img_addr) {
		kernel_addr = load_addr;
		debug("*  kernel: default image load address = 0x%08lx\n",
		      load_addr);
821
#if CONFIG_IS_ENABLED(FIT)
822
	} else if (fit_parse_conf(img_addr, load_addr, &kernel_addr,
823
				  fit_uname_config)) {
824
		debug("*  kernel: config '%s' from image at 0x%08lx\n",
825
		      *fit_uname_config, kernel_addr);
826
	} else if (fit_parse_subimage(img_addr, load_addr, &kernel_addr,
827
				     fit_uname_kernel)) {
828
		debug("*  kernel: subimage '%s' from image at 0x%08lx\n",
829
		      *fit_uname_kernel, kernel_addr);
830 831 832 833 834 835 836 837 838 839
#endif
	} else {
		kernel_addr = simple_strtoul(img_addr, NULL, 16);
		debug("*  kernel: cmdline image address = 0x%08lx\n",
		      kernel_addr);
	}

	return kernel_addr;
}

840 841 842 843 844 845 846 847 848 849 850 851 852
/**
 * genimg_get_kernel_addr() is the simple version of
 * genimg_get_kernel_addr_fit(). It ignores those return FIT strings
 */
ulong genimg_get_kernel_addr(char * const img_addr)
{
	const char *fit_uname_config = NULL;
	const char *fit_uname_kernel = NULL;

	return genimg_get_kernel_addr_fit(img_addr, &fit_uname_config,
					  &fit_uname_kernel);
}

853
/**
854
 * genimg_get_format - get image format type
855 856
 * @img_addr: image start address
 *
857
 * genimg_get_format() checks whether provided address points to a valid
858 859
 * legacy or FIT image.
 *
860 861
 * New uImage format and FDT blob are based on a libfdt. FDT blob
 * may be passed directly or embedded in a FIT image. In both situations
862
 * genimg_get_format() must be able to dectect libfdt header.
863
 *
864 865 866
 * returns:
 *     image format type or IMAGE_FORMAT_INVALID if no image is present
 */
867
int genimg_get_format(const void *img_addr)
868
{
869
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
870
	const image_header_t *hdr;
871

872
	hdr = (const image_header_t *)img_addr;
873
	if (image_check_magic(hdr))
874 875
		return IMAGE_FORMAT_LEGACY;
#endif
876
#if IMAGE_ENABLE_FIT || IMAGE_ENABLE_OF_LIBFDT
877 878
	if (fdt_check_header(img_addr) == 0)
		return IMAGE_FORMAT_FIT;
879 880
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
881 882
	if (android_image_check_header(img_addr) == 0)
		return IMAGE_FORMAT_ANDROID;
883 884
#endif

885
	return IMAGE_FORMAT_INVALID;
886 887
}

888 889 890 891 892 893 894 895 896 897 898
/**
 * fit_has_config - check if there is a valid FIT configuration
 * @images: pointer to the bootm command headers structure
 *
 * fit_has_config() checks if there is a FIT configuration in use
 * (if FTI support is present).
 *
 * returns:
 *     0, no FIT support or no configuration found
 *     1, configuration found
 */
S
Stephen Warren 已提交
899
int genimg_has_config(bootm_headers_t *images)
900
{
901
#if IMAGE_ENABLE_FIT
902 903 904 905 906 907
	if (images->fit_uname_cfg)
		return 1;
#endif
	return 0;
}

908
/**
909
 * boot_get_ramdisk - main ramdisk handling routine
910 911
 * @argc: command argument count
 * @argv: command argument list
912
 * @images: pointer to the bootm images structure
913 914 915 916
 * @arch: expected ramdisk architecture
 * @rd_start: pointer to a ulong variable, will hold ramdisk start address
 * @rd_end: pointer to a ulong variable, will hold ramdisk end
 *
917
 * boot_get_ramdisk() is responsible for finding a valid ramdisk image.
918 919 920 921 922
 * Curently supported are the following ramdisk sources:
 *      - multicomponent kernel/ramdisk image,
 *      - commandline provided address of decicated ramdisk image.
 *
 * returns:
923
 *     0, if ramdisk image was found and valid, or skiped
924 925
 *     rd_start and rd_end are set to ramdisk start/end addresses if
 *     ramdisk image is found and valid
926
 *
927
 *     1, if ramdisk image is found but corrupted, or invalid
928 929
 *     rd_start and rd_end are set to 0 if no ramdisk exists
 */
S
Stephen Warren 已提交
930
int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
931
		uint8_t arch, ulong *rd_start, ulong *rd_end)
932
{
933
	ulong rd_addr, rd_load;
934
	ulong rd_data, rd_len;
935
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
936
	const image_header_t *rd_hdr;
937
#endif
938
	void *buf;
939
#ifdef CONFIG_SUPPORT_RAW_INITRD
940
	char *end;
941
#endif
942
#if IMAGE_ENABLE_FIT
943
	const char	*fit_uname_config = images->fit_uname_cfg;
944 945
	const char	*fit_uname_ramdisk = NULL;
	ulong		default_addr;
946
	int		rd_noffset;
947
#endif
S
Simon Glass 已提交
948
	const char *select = NULL;
949

950 951 952
	*rd_start = 0;
	*rd_end = 0;

953 954 955 956 957
#ifdef CONFIG_ANDROID_BOOT_IMAGE
	/*
	 * Look for an Android boot image.
	 */
	buf = map_sysmem(images->os.start, 0);
958
	if (buf && genimg_get_format(buf) == IMAGE_FORMAT_ANDROID)
959 960 961
		select = argv[0];
#endif

S
Simon Glass 已提交
962 963
	if (argc >= 2)
		select = argv[1];
964

965 966 967 968
	/*
	 * Look for a '-' which indicates to ignore the
	 * ramdisk argument
	 */
S
Simon Glass 已提交
969
	if (select && strcmp(select, "-") ==  0) {
S
Stephen Warren 已提交
970
		debug("## Skipping init Ramdisk\n");
971
		rd_len = rd_data = 0;
S
Simon Glass 已提交
972
	} else if (select || genimg_has_config(images)) {
973
#if IMAGE_ENABLE_FIT
S
Simon Glass 已提交
974
		if (select) {
975 976 977 978 979 980 981 982 983 984 985
			/*
			 * If the init ramdisk comes from the FIT image and
			 * the FIT image address is omitted in the command
			 * line argument, try to use os FIT image address or
			 * default load address.
			 */
			if (images->fit_uname_os)
				default_addr = (ulong)images->fit_hdr_os;
			else
				default_addr = load_addr;

S
Simon Glass 已提交
986 987
			if (fit_parse_conf(select, default_addr,
					   &rd_addr, &fit_uname_config)) {
S
Stephen Warren 已提交
988 989
				debug("*  ramdisk: config '%s' from image at "
						"0x%08lx\n",
990
						fit_uname_config, rd_addr);
S
Simon Glass 已提交
991
			} else if (fit_parse_subimage(select, default_addr,
992
						&rd_addr, &fit_uname_ramdisk)) {
S
Stephen Warren 已提交
993 994
				debug("*  ramdisk: subimage '%s' from image at "
						"0x%08lx\n",
995 996
						fit_uname_ramdisk, rd_addr);
			} else
997
#endif
998
			{
S
Simon Glass 已提交
999
				rd_addr = simple_strtoul(select, NULL, 16);
S
Stephen Warren 已提交
1000 1001
				debug("*  ramdisk: cmdline image address = "
						"0x%08lx\n",
1002 1003
						rd_addr);
			}
1004
#if IMAGE_ENABLE_FIT
1005 1006
		} else {
			/* use FIT configuration provided in first bootm
1007 1008
			 * command argument. If the property is not defined,
			 * quit silently.
1009
			 */
1010
			rd_addr = map_to_sysmem(images->fit_hdr_os);
1011 1012
			rd_noffset = fit_get_node_from_config(images,
					FIT_RAMDISK_PROP, rd_addr);
1013
			if (rd_noffset == -ENOENT)
1014
				return 0;
1015 1016
			else if (rd_noffset < 0)
				return 1;
1017
		}
1018
#endif
1019 1020 1021 1022 1023 1024

		/*
		 * Check if there is an initrd image at the
		 * address provided in the second bootm argument
		 * check image type, for FIT images get FIT node.
		 */
1025 1026
		buf = map_sysmem(rd_addr, 0);
		switch (genimg_get_format(buf)) {
1027
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
1028
		case IMAGE_FORMAT_LEGACY:
S
Stephen Warren 已提交
1029
			printf("## Loading init Ramdisk from Legacy "
1030
					"Image at %08lx ...\n", rd_addr);
1031

1032
			bootstage_mark(BOOTSTAGE_ID_CHECK_RAMDISK);
S
Stephen Warren 已提交
1033
			rd_hdr = image_get_ramdisk(rd_addr, arch,
1034
							images->verify);
1035

1036
			if (rd_hdr == NULL)
1037 1038
				return 1;

S
Stephen Warren 已提交
1039 1040 1041
			rd_data = image_get_data(rd_hdr);
			rd_len = image_get_data_size(rd_hdr);
			rd_load = image_get_load(rd_hdr);
1042
			break;
1043
#endif
1044
#if IMAGE_ENABLE_FIT
1045
		case IMAGE_FORMAT_FIT:
1046
			rd_noffset = fit_image_load(images,
1047
					rd_addr, &fit_uname_ramdisk,
1048
					&fit_uname_config, arch,
1049 1050
					IH_TYPE_RAMDISK,
					BOOTSTAGE_ID_FIT_RD_START,
1051 1052
					FIT_LOAD_OPTIONAL_NON_ZERO,
					&rd_data, &rd_len);
1053
			if (rd_noffset < 0)
1054
				return 1;
1055

1056
			images->fit_hdr_rd = map_sysmem(rd_addr, 0);
1057
			images->fit_uname_rd = fit_uname_ramdisk;
1058
			images->fit_noffset_rd = rd_noffset;
1059
			break;
1060 1061 1062 1063 1064 1065
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
		case IMAGE_FORMAT_ANDROID:
			android_image_get_ramdisk((void *)images->os.start,
				&rd_data, &rd_len);
			break;
1066 1067
#endif
		default:
1068
#ifdef CONFIG_SUPPORT_RAW_INITRD
S
Simon Glass 已提交
1069 1070 1071 1072
			end = NULL;
			if (select)
				end = strchr(select, ':');
			if (end) {
1073 1074 1075 1076 1077 1078 1079 1080 1081
				rd_len = simple_strtoul(++end, NULL, 16);
				rd_data = rd_addr;
			} else
#endif
			{
				puts("Wrong Ramdisk Image Format\n");
				rd_data = rd_len = rd_load = 0;
				return 1;
			}
1082 1083
		}
	} else if (images->legacy_hdr_valid &&
S
Stephen Warren 已提交
1084 1085 1086
			image_check_type(&images->legacy_hdr_os_copy,
						IH_TYPE_MULTI)) {

1087
		/*
1088 1089
		 * Now check if we have a legacy mult-component image,
		 * get second entry data start address and len.
1090
		 */
1091
		bootstage_mark(BOOTSTAGE_ID_RAMDISK);
S
Stephen Warren 已提交
1092
		printf("## Loading init Ramdisk from multi component "
1093
				"Legacy Image at %08lx ...\n",
1094 1095
				(ulong)images->legacy_hdr_os);

S
Stephen Warren 已提交
1096
		image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
1097
	} else {
1098 1099 1100
		/*
		 * no initrd image
		 */
1101
		bootstage_mark(BOOTSTAGE_ID_NO_RAMDISK);
1102 1103 1104 1105
		rd_len = rd_data = 0;
	}

	if (!rd_data) {
S
Stephen Warren 已提交
1106
		debug("## No init Ramdisk\n");
1107 1108 1109 1110
	} else {
		*rd_start = rd_data;
		*rd_end = rd_data + rd_len;
	}
S
Stephen Warren 已提交
1111
	debug("   ramdisk start = 0x%08lx, ramdisk end = 0x%08lx\n",
1112
			*rd_start, *rd_end);
1113 1114

	return 0;
1115
}
1116

1117
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
1118
/**
1119
 * boot_ramdisk_high - relocate init ramdisk
1120
 * @lmb: pointer to lmb handle, will be used for memory mgmt
1121 1122 1123 1124 1125 1126 1127
 * @rd_data: ramdisk data start address
 * @rd_len: ramdisk data length
 * @initrd_start: pointer to a ulong variable, will hold final init ramdisk
 *      start address (after possible relocation)
 * @initrd_end: pointer to a ulong variable, will hold final init ramdisk
 *      end address (after possible relocation)
 *
1128
 * boot_ramdisk_high() takes a relocation hint from "initrd_high" environment
1129 1130
 * variable and if requested ramdisk data is moved to a specified location.
 *
1131 1132 1133 1134
 * Initrd_start and initrd_end are set to final (after relocation) ramdisk
 * start/end addresses if ramdisk image start and len were provided,
 * otherwise set initrd_start and initrd_end set to zeros.
 *
1135
 * returns:
1136 1137
 *      0 - success
 *     -1 - failure
1138
 */
S
Stephen Warren 已提交
1139
int boot_ramdisk_high(struct lmb *lmb, ulong rd_data, ulong rd_len,
1140
		  ulong *initrd_start, ulong *initrd_end)
1141 1142 1143 1144 1145
{
	char	*s;
	ulong	initrd_high;
	int	initrd_copy_to_ram = 1;

1146 1147
	s = env_get("initrd_high");
	if (s) {
1148 1149 1150
		/* a value of "no" or a similar string will act like 0,
		 * turning the "load high" feature off. This is intentional.
		 */
S
Stephen Warren 已提交
1151
		initrd_high = simple_strtoul(s, NULL, 16);
1152 1153 1154
		if (initrd_high == ~0)
			initrd_copy_to_ram = 0;
	} else {
1155
		initrd_high = env_get_bootm_mapsize() + env_get_bootm_low();
1156 1157
	}

1158

S
Stephen Warren 已提交
1159
	debug("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
1160 1161 1162 1163
			initrd_high, initrd_copy_to_ram);

	if (rd_data) {
		if (!initrd_copy_to_ram) {	/* zero-copy ramdisk support */
S
Stephen Warren 已提交
1164
			debug("   in-place initrd\n");
1165 1166
			*initrd_start = rd_data;
			*initrd_end = rd_data + rd_len;
1167
			lmb_reserve(lmb, rd_data, rd_len);
1168
		} else {
1169
			if (initrd_high)
S
Stephen Warren 已提交
1170 1171
				*initrd_start = (ulong)lmb_alloc_base(lmb,
						rd_len, 0x1000, initrd_high);
1172
			else
S
Stephen Warren 已提交
1173 1174
				*initrd_start = (ulong)lmb_alloc(lmb, rd_len,
								 0x1000);
1175 1176

			if (*initrd_start == 0) {
S
Stephen Warren 已提交
1177
				puts("ramdisk - allocation error\n");
1178
				goto error;
1179
			}
1180
			bootstage_mark(BOOTSTAGE_ID_COPY_RAMDISK);
1181 1182

			*initrd_end = *initrd_start + rd_len;
S
Stephen Warren 已提交
1183
			printf("   Loading Ramdisk to %08lx, end %08lx ... ",
1184 1185
					*initrd_start, *initrd_end);

S
Stephen Warren 已提交
1186
			memmove_wd((void *)*initrd_start,
1187 1188
					(void *)rd_data, rd_len, CHUNKSZ);

1189 1190 1191 1192 1193 1194
#ifdef CONFIG_MP
			/*
			 * Ensure the image is flushed to memory to handle
			 * AMP boot scenarios in which we might not be
			 * HW cache coherent
			 */
1195 1196
			flush_cache((unsigned long)*initrd_start,
				    ALIGN(rd_len, ARCH_DMA_MINALIGN));
1197
#endif
S
Stephen Warren 已提交
1198
			puts("OK\n");
1199 1200 1201 1202 1203
		}
	} else {
		*initrd_start = 0;
		*initrd_end = 0;
	}
S
Stephen Warren 已提交
1204
	debug("   ramdisk load start = 0x%08lx, ramdisk load end = 0x%08lx\n",
1205
			*initrd_start, *initrd_end);
1206

1207
	return 0;
1208

1209 1210
error:
	return -1;
1211
}
1212
#endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
1213

1214 1215 1216
int boot_get_setup(bootm_headers_t *images, uint8_t arch,
		   ulong *setup_start, ulong *setup_len)
{
1217
#if IMAGE_ENABLE_FIT
1218 1219 1220 1221 1222 1223
	return boot_get_setup_fit(images, arch, setup_start, setup_len);
#else
	return -ENOENT;
#endif
}

1224
#if IMAGE_ENABLE_FIT
1225
#if defined(CONFIG_FPGA)
1226 1227 1228 1229 1230 1231 1232
int boot_get_fpga(int argc, char * const argv[], bootm_headers_t *images,
		  uint8_t arch, const ulong *ld_start, ulong * const ld_len)
{
	ulong tmp_img_addr, img_data, img_len;
	void *buf;
	int conf_noffset;
	int fit_img_result;
1233
	const char *uname, *name;
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
	int err;
	int devnum = 0; /* TODO support multi fpga platforms */

	/* Check to see if the images struct has a FIT configuration */
	if (!genimg_has_config(images)) {
		debug("## FIT configuration was not specified\n");
		return 0;
	}

	/*
	 * Obtain the os FIT header from the images struct
	 */
	tmp_img_addr = map_to_sysmem(images->fit_hdr_os);
	buf = map_sysmem(tmp_img_addr, 0);
	/*
	 * Check image type. For FIT images get FIT node
	 * and attempt to locate a generic binary.
	 */
	switch (genimg_get_format(buf)) {
	case IMAGE_FORMAT_FIT:
		conf_noffset = fit_conf_get_node(buf, images->fit_uname_cfg);

1256 1257 1258
		uname = fdt_stringlist_get(buf, conf_noffset, FIT_FPGA_PROP, 0,
					   NULL);
		if (!uname) {
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279
			debug("## FPGA image is not specified\n");
			return 0;
		}
		fit_img_result = fit_image_load(images,
						tmp_img_addr,
						(const char **)&uname,
						&(images->fit_uname_cfg),
						arch,
						IH_TYPE_FPGA,
						BOOTSTAGE_ID_FPGA_INIT,
						FIT_LOAD_OPTIONAL_NON_ZERO,
						&img_data, &img_len);

		debug("FPGA image (%s) loaded to 0x%lx/size 0x%lx\n",
		      uname, img_data, img_len);

		if (fit_img_result < 0) {
			/* Something went wrong! */
			return fit_img_result;
		}

1280
		if (!fpga_is_partial_data(devnum, img_len)) {
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
			name = "full";
			err = fpga_loadbitstream(devnum, (char *)img_data,
						 img_len, BIT_FULL);
			if (err)
				err = fpga_load(devnum, (const void *)img_data,
						img_len, BIT_FULL);
		} else {
			name = "partial";
			err = fpga_loadbitstream(devnum, (char *)img_data,
						 img_len, BIT_PARTIAL);
			if (err)
				err = fpga_load(devnum, (const void *)img_data,
						img_len, BIT_PARTIAL);
		}

		if (err)
1297 1298 1299
			return err;

		printf("   Programming %s bitstream... OK\n", name);
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
		break;
	default:
		printf("The given image format is not supported (corrupt?)\n");
		return 1;
	}

	return 0;
}
#endif

1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
static void fit_loadable_process(uint8_t img_type,
				 ulong img_data,
				 ulong img_len)
{
	int i;
	const unsigned int count =
			ll_entry_count(struct fit_loadable_tbl, fit_loadable);
	struct fit_loadable_tbl *fit_loadable_handler =
			ll_entry_start(struct fit_loadable_tbl, fit_loadable);
	/* For each loadable handler */
	for (i = 0; i < count; i++, fit_loadable_handler++)
		/* matching this type */
		if (fit_loadable_handler->type == img_type)
			/* call that handler with this image data */
			fit_loadable_handler->handler(img_data, img_len);
}

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
int boot_get_loadable(int argc, char * const argv[], bootm_headers_t *images,
		uint8_t arch, const ulong *ld_start, ulong * const ld_len)
{
	/*
	 * These variables are used to hold the current image location
	 * in system memory.
	 */
	ulong tmp_img_addr;
	/*
	 * These two variables are requirements for fit_image_load, but
	 * their values are not used
	 */
	ulong img_data, img_len;
	void *buf;
	int loadables_index;
	int conf_noffset;
	int fit_img_result;
1344
	const char *uname;
1345
	uint8_t img_type;
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366

	/* Check to see if the images struct has a FIT configuration */
	if (!genimg_has_config(images)) {
		debug("## FIT configuration was not specified\n");
		return 0;
	}

	/*
	 * Obtain the os FIT header from the images struct
	 */
	tmp_img_addr = map_to_sysmem(images->fit_hdr_os);
	buf = map_sysmem(tmp_img_addr, 0);
	/*
	 * Check image type. For FIT images get FIT node
	 * and attempt to locate a generic binary.
	 */
	switch (genimg_get_format(buf)) {
	case IMAGE_FORMAT_FIT:
		conf_noffset = fit_conf_get_node(buf, images->fit_uname_cfg);

		for (loadables_index = 0;
1367 1368 1369
		     uname = fdt_stringlist_get(buf, conf_noffset,
					FIT_LOADABLE_PROP, loadables_index,
					NULL), uname;
1370 1371 1372 1373
		     loadables_index++)
		{
			fit_img_result = fit_image_load(images,
				tmp_img_addr,
1374
				&uname,
1375 1376 1377 1378 1379 1380 1381 1382 1383
				&(images->fit_uname_cfg), arch,
				IH_TYPE_LOADABLE,
				BOOTSTAGE_ID_FIT_LOADABLE_START,
				FIT_LOAD_OPTIONAL_NON_ZERO,
				&img_data, &img_len);
			if (fit_img_result < 0) {
				/* Something went wrong! */
				return fit_img_result;
			}
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398

			fit_img_result = fit_image_get_node(buf, uname);
			if (fit_img_result < 0) {
				/* Something went wrong! */
				return fit_img_result;
			}
			fit_img_result = fit_image_get_type(buf,
							    fit_img_result,
							    &img_type);
			if (fit_img_result < 0) {
				/* Something went wrong! */
				return fit_img_result;
			}

			fit_loadable_process(img_type, img_data, img_len);
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
		}
		break;
	default:
		printf("The given image format is not supported (corrupt?)\n");
		return 1;
	}

	return 0;
}
#endif

1410
#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
1411
/**
1412
 * boot_get_cmdline - allocate and initialize kernel cmdline
1413
 * @lmb: pointer to lmb handle, will be used for memory mgmt
1414 1415 1416
 * @cmd_start: pointer to a ulong variable, will hold cmdline start
 * @cmd_end: pointer to a ulong variable, will hold cmdline end
 *
1417
 * boot_get_cmdline() allocates space for kernel command line below
S
Shyam Saini 已提交
1418
 * BOOTMAPSZ + env_get_bootm_low() address. If "bootargs" U-Boot environment
1419 1420 1421 1422
 * variable is present its contents is copied to allocated kernel
 * command line.
 *
 * returns:
1423 1424
 *      0 - success
 *     -1 - failure
1425
 */
S
Stephen Warren 已提交
1426
int boot_get_cmdline(struct lmb *lmb, ulong *cmd_start, ulong *cmd_end)
1427 1428 1429 1430
{
	char *cmdline;
	char *s;

1431
	cmdline = (char *)(ulong)lmb_alloc_base(lmb, CONFIG_SYS_BARGSIZE, 0xf,
1432
				env_get_bootm_mapsize() + env_get_bootm_low());
1433 1434 1435

	if (cmdline == NULL)
		return -1;
1436

1437 1438
	s = env_get("bootargs");
	if (!s)
1439 1440 1441 1442 1443 1444 1445
		s = "";

	strcpy(cmdline, s);

	*cmd_start = (ulong) & cmdline[0];
	*cmd_end = *cmd_start + strlen(cmdline);

S
Stephen Warren 已提交
1446
	debug("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end);
1447

1448
	return 0;
1449
}
1450
#endif /* CONFIG_SYS_BOOT_GET_CMDLINE */
1451

1452
#ifdef CONFIG_SYS_BOOT_GET_KBD
1453
/**
1454
 * boot_get_kbd - allocate and initialize kernel copy of board info
1455
 * @lmb: pointer to lmb handle, will be used for memory mgmt
1456 1457
 * @kbd: double pointer to board info data
 *
1458
 * boot_get_kbd() allocates space for kernel copy of board info data below
1459
 * BOOTMAPSZ + env_get_bootm_low() address and kernel board info is initialized
1460
 * with the current u-boot board info data.
1461 1462
 *
 * returns:
1463 1464
 *      0 - success
 *     -1 - failure
1465
 */
S
Stephen Warren 已提交
1466
int boot_get_kbd(struct lmb *lmb, bd_t **kbd)
1467
{
1468
	*kbd = (bd_t *)(ulong)lmb_alloc_base(lmb, sizeof(bd_t), 0xf,
1469
				env_get_bootm_mapsize() + env_get_bootm_low());
1470 1471 1472
	if (*kbd == NULL)
		return -1;

1473 1474
	**kbd = *(gd->bd);

S
Stephen Warren 已提交
1475
	debug("## kernel board info at 0x%08lx\n", (ulong)*kbd);
1476 1477 1478 1479 1480

#if defined(DEBUG) && defined(CONFIG_CMD_BDI)
	do_bdinfo(NULL, 0, 0, NULL);
#endif

1481
	return 0;
1482
}
1483
#endif /* CONFIG_SYS_BOOT_GET_KBD */
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519

#ifdef CONFIG_LMB
int image_setup_linux(bootm_headers_t *images)
{
	ulong of_size = images->ft_len;
	char **of_flat_tree = &images->ft_addr;
	struct lmb *lmb = &images->lmb;
	int ret;

	if (IMAGE_ENABLE_OF_LIBFDT)
		boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);

	if (IMAGE_BOOT_GET_CMDLINE) {
		ret = boot_get_cmdline(lmb, &images->cmdline_start,
				&images->cmdline_end);
		if (ret) {
			puts("ERROR with allocation of cmdline\n");
			return ret;
		}
	}

	if (IMAGE_ENABLE_OF_LIBFDT) {
		ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
		if (ret)
			return ret;
	}

	if (IMAGE_ENABLE_OF_LIBFDT && of_size) {
		ret = image_setup_libfdt(images, *of_flat_tree, of_size, lmb);
		if (ret)
			return ret;
	}

	return 0;
}
#endif /* CONFIG_LMB */
1520
#endif /* !USE_HOSTCC */