bootm.c 18.7 KB
Newer Older
wdenk's avatar
wdenk committed
1
/*
2
 * (C) Copyright 2000-2009
wdenk's avatar
wdenk committed
3 4
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
5
 * SPDX-License-Identifier:	GPL-2.0+
wdenk's avatar
wdenk committed
6 7 8 9 10 11
 */

/*
 * Boot support
 */
#include <common.h>
12
#include <bootm.h>
wdenk's avatar
wdenk committed
13
#include <command.h>
14
#include <environment.h>
15
#include <errno.h>
16
#include <image.h>
17
#include <lmb.h>
18
#include <malloc.h>
19
#include <mapmem.h>
20
#include <nand.h>
wdenk's avatar
wdenk committed
21
#include <asm/byteorder.h>
22
#include <linux/compiler.h>
23 24 25
#include <linux/ctype.h>
#include <linux/err.h>
#include <u-boot/zlib.h>
26

27
DECLARE_GLOBAL_DATA_PTR;
28

29
#if defined(CONFIG_CMD_IMI)
30
static int image_info(unsigned long addr);
wdenk's avatar
wdenk committed
31
#endif
32

33
#if defined(CONFIG_CMD_IMLS)
34
#include <flash.h>
35
#include <mtd/cfi_flash.h>
36
extern flash_info_t flash_info[]; /* info for FLASH chips */
37 38 39
#endif

#if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
40
static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
41 42
#endif

43
bootm_headers_t images;		/* pointers to os/initrd/fdt images */
44

Kumar Gala's avatar
Kumar Gala committed
45 46
/* we overload the cmd field with our state machine info instead of a
 * function pointer */
47
static cmd_tbl_t cmd_bootm_sub[] = {
Kumar Gala's avatar
Kumar Gala committed
48 49
	U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""),
	U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""),
50
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
Kumar Gala's avatar
Kumar Gala committed
51 52 53 54 55 56
	U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""),
#endif
#ifdef CONFIG_OF_LIBFDT
	U_BOOT_CMD_MKENT(fdt, 0, 1, (void *)BOOTM_STATE_FDT, "", ""),
#endif
	U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),
57
	U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),
Kumar Gala's avatar
Kumar Gala committed
58
	U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""),
59
	U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""),
Kumar Gala's avatar
Kumar Gala committed
60 61 62
	U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),
};

63
static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
64
			char * const argv[])
Kumar Gala's avatar
Kumar Gala committed
65 66
{
	int ret = 0;
Simon Glass's avatar
Simon Glass committed
67
	long state;
Kumar Gala's avatar
Kumar Gala committed
68 69
	cmd_tbl_t *c;

Simon Glass's avatar
Simon Glass committed
70 71
	c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
	argc--; argv++;
Kumar Gala's avatar
Kumar Gala committed
72 73

	if (c) {
Simon Glass's avatar
Simon Glass committed
74
		state = (long)c->cmd;
Simon Glass's avatar
Simon Glass committed
75
		if (state == BOOTM_STATE_START)
76
			state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER;
77 78
	} else {
		/* Unrecognized command */
79
		return CMD_RET_USAGE;
Kumar Gala's avatar
Kumar Gala committed
80 81
	}

82 83
	if (((state & BOOTM_STATE_START) != BOOTM_STATE_START) &&
	    images.state >= state) {
84
		printf("Trying to execute a command out of order\n");
85
		return CMD_RET_USAGE;
Kumar Gala's avatar
Kumar Gala committed
86 87
	}

88
	ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0);
Kumar Gala's avatar
Kumar Gala committed
89 90 91 92

	return ret;
}

93 94 95
/*******************************************************************/
/* bootm - boot application image from image in memory */
/*******************************************************************/
96

97
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
98
{
99
#ifdef CONFIG_NEEDS_MANUAL_RELOC
100
	static int relocated = 0;
101 102 103

	if (!relocated) {
		int i;
104 105 106 107 108

		/* relocate names of sub-command table */
		for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++)
			cmd_bootm_sub[i].name += gd->reloc_off;

109 110
		relocated = 1;
	}
111
#endif
112

Kumar Gala's avatar
Kumar Gala committed
113
	/* determine if we have a sub command */
Simon Glass's avatar
Simon Glass committed
114 115
	argc--; argv++;
	if (argc > 0) {
Kumar Gala's avatar
Kumar Gala committed
116 117
		char *endp;

Simon Glass's avatar
Simon Glass committed
118 119
		simple_strtoul(argv[0], &endp, 16);
		/* endp pointing to NULL means that argv[0] was just a
Kumar Gala's avatar
Kumar Gala committed
120 121 122 123 124 125 126 127 128 129 130
		 * valid number, pass it along to the normal bootm processing
		 *
		 * If endp is ':' or '#' assume a FIT identifier so pass
		 * along for normal processing.
		 *
		 * Right now we assume the first arg should never be '-'
		 */
		if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
			return do_bootm_subcommand(cmdtp, flag, argc, argv);
	}

131 132
	return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
		BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
133 134 135 136
		BOOTM_STATE_LOADOS |
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
		BOOTM_STATE_OS_CMDLINE |
#endif
137 138
		BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
		BOOTM_STATE_OS_GO, &images, 1);
wdenk's avatar
wdenk committed
139 140
}

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
{
	const char *ep = getenv("autostart");

	if (ep && !strcmp(ep, "yes")) {
		char *local_args[2];
		local_args[0] = (char *)cmd;
		local_args[1] = NULL;
		printf("Automatic boot of image at addr 0x%08lX ...\n", load_addr);
		return do_bootm(cmdtp, 0, 1, local_args);
	}

	return 0;
}

156 157
#ifdef CONFIG_SYS_LONGHELP
static char bootm_help_text[] =
158 159 160
	"[addr [arg ...]]\n    - boot application image stored in memory\n"
	"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
	"\t'arg' can be the address of an initrd image\n"
161
#if defined(CONFIG_OF_LIBFDT)
162
	"\tWhen booting a Linux kernel which requires a flat device-tree\n"
Detlev Zundel's avatar
Detlev Zundel committed
163
	"\ta third argument is required which is the address of the\n"
164 165 166 167
	"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
	"\tuse a '-' for the second argument. If you do not pass a third\n"
	"\ta bd_info struct will be passed instead\n"
#endif
168 169 170 171 172 173 174 175
#if defined(CONFIG_FIT)
	"\t\nFor the new multi component uImage format (FIT) addresses\n"
	"\tmust be extened to include component or configuration unit name:\n"
	"\taddr:<subimg_uname> - direct component image specification\n"
	"\taddr#<conf_uname>   - configuration specification\n"
	"\tUse iminfo command to get the list of existing component\n"
	"\timages and configurations.\n"
#endif
Kumar Gala's avatar
Kumar Gala committed
176 177 178 179 180
	"\nSub-commands to do part of the bootm sequence.  The sub-commands "
	"must be\n"
	"issued in the order below (it's ok to not issue all sub-commands):\n"
	"\tstart [addr [arg ...]]\n"
	"\tloados  - load OS image\n"
181
#if defined(CONFIG_SYS_BOOT_RAMDISK_HIGH)
Kumar Gala's avatar
Kumar Gala committed
182 183 184 185 186 187
	"\tramdisk - relocate initrd, set env initrd_start/initrd_end\n"
#endif
#if defined(CONFIG_OF_LIBFDT)
	"\tfdt     - relocate flat device tree\n"
#endif
	"\tcmdline - OS specific command line processing/setup\n"
188
	"\tbdt     - OS specific bd_t processing\n"
Kumar Gala's avatar
Kumar Gala committed
189
	"\tprep    - OS specific prep before relocation or go\n"
190 191 192
#if defined(CONFIG_TRACE)
	"\tfake    - OS specific fake start without go\n"
#endif
193 194 195 196 197 198
	"\tgo      - start OS";
#endif

U_BOOT_CMD(
	bootm,	CONFIG_SYS_MAXARGS,	1,	do_bootm,
	"boot application image from memory", bootm_help_text
wdenk's avatar
wdenk committed
199
);
wdenk's avatar
wdenk committed
200

201 202 203
/*******************************************************************/
/* bootd - boot default image */
/*******************************************************************/
204
#if defined(CONFIG_CMD_BOOTD)
205
int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
206
{
207
	return run_command(getenv("bootcmd"), flag);
wdenk's avatar
wdenk committed
208 209
}

210
U_BOOT_CMD(
211
	boot,	1,	1,	do_bootd,
Peter Tyser's avatar
Peter Tyser committed
212
	"boot default, i.e., run 'bootcmd'",
213
	""
214
);
wdenk's avatar
wdenk committed
215

216
/* keep old command name "bootd" for backward compatibility */
217
U_BOOT_CMD(
218
	bootd, 1,	1,	do_bootd,
Peter Tyser's avatar
Peter Tyser committed
219
	"boot default, i.e., run 'bootcmd'",
220
	""
wdenk's avatar
wdenk committed
221
);
wdenk's avatar
wdenk committed
222 223 224 225

#endif


226 227 228
/*******************************************************************/
/* iminfo - print header info for a requested image */
/*******************************************************************/
229
#if defined(CONFIG_CMD_IMI)
230
static int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
231 232 233
{
	int	arg;
	ulong	addr;
234
	int	rcode = 0;
wdenk's avatar
wdenk committed
235 236

	if (argc < 2) {
237
		return image_info(load_addr);
wdenk's avatar
wdenk committed
238 239
	}

240
	for (arg = 1; arg < argc; ++arg) {
241 242
		addr = simple_strtoul(argv[arg], NULL, 16);
		if (image_info(addr) != 0)
243
			rcode = 1;
wdenk's avatar
wdenk committed
244 245 246 247
	}
	return rcode;
}

248
static int image_info(ulong addr)
wdenk's avatar
wdenk committed
249
{
250
	void *hdr = (void *)addr;
wdenk's avatar
wdenk committed
251

252
	printf("\n## Checking Image at %08lx ...\n", addr);
wdenk's avatar
wdenk committed
253

254
	switch (genimg_get_format(hdr)) {
255
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
256
	case IMAGE_FORMAT_LEGACY:
257 258 259
		puts("   Legacy image found\n");
		if (!image_check_magic(hdr)) {
			puts("   Bad Magic Number\n");
260 261
			return 1;
		}
wdenk's avatar
wdenk committed
262

263 264
		if (!image_check_hcrc(hdr)) {
			puts("   Bad Header Checksum\n");
265
			return 1;
wdenk's avatar
wdenk committed
266 267
		}

268
		image_print_contents(hdr);
wdenk's avatar
wdenk committed
269

270 271 272
		puts("   Verifying Checksum ... ");
		if (!image_check_dcrc(hdr)) {
			puts("   Bad Data CRC\n");
273
			return 1;
wdenk's avatar
wdenk committed
274
		}
275
		puts("OK\n");
276
		return 0;
277
#endif
278 279
#if defined(CONFIG_FIT)
	case IMAGE_FORMAT_FIT:
280
		puts("   FIT image found\n");
wdenk's avatar
wdenk committed
281

282 283
		if (!fit_check_format(hdr)) {
			puts("Bad FIT image format!\n");
284
			return 1;
wdenk's avatar
wdenk committed
285 286
		}

287
		fit_print_contents(hdr);
288

289
		if (!fit_all_image_verify(hdr)) {
290
			puts("Bad hash in FIT image!\n");
291 292 293
			return 1;
		}

294 295 296
		return 0;
#endif
	default:
297
		puts("Unknown image format!\n");
298
		break;
wdenk's avatar
wdenk committed
299 300
	}

301
	return 1;
wdenk's avatar
wdenk committed
302
}
303 304

U_BOOT_CMD(
305
	iminfo,	CONFIG_SYS_MAXARGS,	1,	do_iminfo,
Peter Tyser's avatar
Peter Tyser committed
306
	"print header information for application image",
wdenk's avatar
wdenk committed
307 308 309
	"addr [addr ...]\n"
	"    - print header information for application image starting at\n"
	"      address 'addr' in memory; this includes verification of the\n"
310
	"      image contents (magic number, header and payload checksums)"
wdenk's avatar
wdenk committed
311
);
312
#endif
313

314

315 316 317
/*******************************************************************/
/* imls - list all images found in flash */
/*******************************************************************/
318
#if defined(CONFIG_CMD_IMLS)
319
static int do_imls_nor(void)
320 321 322
{
	flash_info_t *info;
	int i, j;
323
	void *hdr;
324

325
	for (i = 0, info = &flash_info[0];
326
		i < CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
327

328 329
		if (info->flash_id == FLASH_UNKNOWN)
			goto next_bank;
330
		for (j = 0; j < info->sector_count; ++j) {
331

332 333
			hdr = (void *)info->start[j];
			if (!hdr)
334
				goto next_sector;
335

336
			switch (genimg_get_format(hdr)) {
337
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
338
			case IMAGE_FORMAT_LEGACY:
339
				if (!image_check_hcrc(hdr))
340 341
					goto next_sector;

342 343
				printf("Legacy Image at %08lX:\n", (ulong)hdr);
				image_print_contents(hdr);
344

345 346 347
				puts("   Verifying Checksum ... ");
				if (!image_check_dcrc(hdr)) {
					puts("Bad Data CRC\n");
348
				} else {
349
					puts("OK\n");
350 351
				}
				break;
352
#endif
353 354
#if defined(CONFIG_FIT)
			case IMAGE_FORMAT_FIT:
355
				if (!fit_check_format(hdr))
356 357
					goto next_sector;

358 359
				printf("FIT Image at %08lX:\n", (ulong)hdr);
				fit_print_contents(hdr);
360
				break;
361
#endif
362
			default:
363
				goto next_sector;
364
			}
365

366
next_sector:		;
367
		}
368
next_bank:	;
369
	}
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
	return 0;
}
#endif

#if defined(CONFIG_CMD_IMLS_NAND)
static int nand_imls_legacyimage(nand_info_t *nand, int nand_dev, loff_t off,
		size_t len)
{
	void *imgdata;
	int ret;

	imgdata = malloc(len);
	if (!imgdata) {
		printf("May be a Legacy Image at NAND device %d offset %08llX:\n",
				nand_dev, off);
		printf("   Low memory(cannot allocate memory for image)\n");
		return -ENOMEM;
	}

	ret = nand_read_skip_bad(nand, off, &len,
			imgdata);
	if (ret < 0 && ret != -EUCLEAN) {
		free(imgdata);
		return ret;
	}

	if (!image_check_hcrc(imgdata)) {
		free(imgdata);
		return 0;
	}

	printf("Legacy Image at NAND device %d offset %08llX:\n",
			nand_dev, off);
	image_print_contents(imgdata);

	puts("   Verifying Checksum ... ");
	if (!image_check_dcrc(imgdata))
		puts("Bad Data CRC\n");
	else
		puts("OK\n");

	free(imgdata);

	return 0;
}

static int nand_imls_fitimage(nand_info_t *nand, int nand_dev, loff_t off,
		size_t len)
{
	void *imgdata;
	int ret;

	imgdata = malloc(len);
	if (!imgdata) {
		printf("May be a FIT Image at NAND device %d offset %08llX:\n",
				nand_dev, off);
		printf("   Low memory(cannot allocate memory for image)\n");
		return -ENOMEM;
	}

	ret = nand_read_skip_bad(nand, off, &len,
			imgdata);
	if (ret < 0 && ret != -EUCLEAN) {
		free(imgdata);
		return ret;
	}

	if (!fit_check_format(imgdata)) {
		free(imgdata);
		return 0;
	}

	printf("FIT Image at NAND device %d offset %08llX:\n", nand_dev, off);

	fit_print_contents(imgdata);
	free(imgdata);

	return 0;
}

static int do_imls_nand(void)
{
	nand_info_t *nand;
	int nand_dev = nand_curr_device;
	size_t len;
	loff_t off;
	u32 buffer[16];

	if (nand_dev < 0 || nand_dev >= CONFIG_SYS_MAX_NAND_DEVICE) {
		puts("\nNo NAND devices available\n");
		return -ENODEV;
	}

	printf("\n");

	for (nand_dev = 0; nand_dev < CONFIG_SYS_MAX_NAND_DEVICE; nand_dev++) {
		nand = &nand_info[nand_dev];
		if (!nand->name || !nand->size)
			continue;

		for (off = 0; off < nand->size; off += nand->erasesize) {
			const image_header_t *header;
			int ret;

			if (nand_block_isbad(nand, off))
				continue;

			len = sizeof(buffer);

			ret = nand_read(nand, off, &len, (u8 *)buffer);
			if (ret < 0 && ret != -EUCLEAN) {
				printf("NAND read error %d at offset %08llX\n",
						ret, off);
				continue;
			}

			switch (genimg_get_format(buffer)) {
487
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
488 489 490 491 492 493
			case IMAGE_FORMAT_LEGACY:
				header = (const image_header_t *)buffer;

				len = image_get_image_size(header);
				nand_imls_legacyimage(nand, nand_dev, off, len);
				break;
494
#endif
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
#if defined(CONFIG_FIT)
			case IMAGE_FORMAT_FIT:
				len = fit_get_size(buffer);
				nand_imls_fitimage(nand, nand_dev, off, len);
				break;
#endif
			}
		}
	}

	return 0;
}
#endif

#if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int ret_nor = 0, ret_nand = 0;

#if defined(CONFIG_CMD_IMLS)
	ret_nor = do_imls_nor();
#endif

#if defined(CONFIG_CMD_IMLS_NAND)
	ret_nand = do_imls_nand();
#endif

	if (ret_nor)
		return ret_nor;

	if (ret_nand)
		return ret_nand;
527

528 529
	return (0);
}
530

531 532
U_BOOT_CMD(
	imls,	1,		1,	do_imls,
Peter Tyser's avatar
Peter Tyser committed
533
	"list all images found in flash",
534
	"\n"
535 536
	"    - Prints information about all images found at sector/block\n"
	"      boundaries in nor/nand flash."
537
);
538
#endif
wdenk's avatar
wdenk committed
539

540 541
#ifdef CONFIG_CMD_BOOTZ

542
int __weak bootz_setup(ulong image, ulong *start, ulong *end)
543 544 545 546 547 548 549 550 551 552 553 554 555 556
{
	/* Please define bootz_setup() for your platform */

	puts("Your platform's zImage format isn't supported yet!\n");
	return -1;
}

/*
 * zImage booting support
 */
static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,
			char * const argv[], bootm_headers_t *images)
{
	int ret;
557
	ulong zi_start, zi_end;
558

559 560
	ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
			      images, 1);
561 562

	/* Setup Linux kernel zImage entry point */
563
	if (!argc) {
564 565 566 567
		images->ep = load_addr;
		debug("*  kernel: default image load address = 0x%08lx\n",
				load_addr);
	} else {
568
		images->ep = simple_strtoul(argv[0], NULL, 16);
569 570 571 572
		debug("*  kernel: cmdline image address = 0x%08lx\n",
			images->ep);
	}

573
	ret = bootz_setup(images->ep, &zi_start, &zi_end);
574 575 576 577 578
	if (ret != 0)
		return 1;

	lmb_reserve(&images->lmb, images->ep, zi_end - zi_start);

579 580 581 582
	/*
	 * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
	 * have a header that provide this informaiton.
	 */
583
	if (bootm_find_images(flag, argc, argv))
584
		return 1;
585

586
	return 0;
587 588
}

589
int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
590
{
591
	int ret;
592

593 594 595
	/* Consume 'bootz' */
	argc--; argv++;

596 597 598
	if (bootz_start(cmdtp, flag, argc, argv, &images))
		return 1;

599 600 601 602 603 604
	/*
	 * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
	 * disable interrupts ourselves
	 */
	bootm_disable_interrupts();

605
	images.os.os = IH_OS_LINUX;
606
	ret = do_bootm_states(cmdtp, flag, argc, argv,
607 608
			      BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
			      BOOTM_STATE_OS_GO,
609
			      &images, 1);
610

611
	return ret;
612 613
}

614 615
#ifdef CONFIG_SYS_LONGHELP
static char bootz_help_text[] =
616 617
	"[addr [initrd[:size]] [fdt]]\n"
	"    - boot Linux zImage stored in memory\n"
618
	"\tThe argument 'initrd' is optional and specifies the address\n"
619 620
	"\tof the initrd in memory. The optional argument ':size' allows\n"
	"\tspecifying the size of RAW initrd.\n"
621 622 623 624 625 626 627
#if defined(CONFIG_OF_LIBFDT)
	"\tWhen booting a Linux kernel which requires a flat device-tree\n"
	"\ta third argument is required which is the address of the\n"
	"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
	"\tuse a '-' for the second argument. If you do not pass a third\n"
	"\ta bd_info struct will be passed instead\n"
#endif
628 629 630 631 632 633
	"";
#endif

U_BOOT_CMD(
	bootz,	CONFIG_SYS_MAXARGS,	1,	do_bootz,
	"boot Linux zImage image from memory", bootz_help_text
634 635
);
#endif	/* CONFIG_CMD_BOOTZ */
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657

#ifdef CONFIG_CMD_BOOTI
/* See Documentation/arm64/booting.txt in the Linux kernel */
struct Image_header {
	uint32_t	code0;		/* Executable code */
	uint32_t	code1;		/* Executable code */
	uint64_t	text_offset;	/* Image load offset, LE */
	uint64_t	image_size;	/* Effective Image size, LE */
	uint64_t	res1;		/* reserved */
	uint64_t	res2;		/* reserved */
	uint64_t	res3;		/* reserved */
	uint64_t	res4;		/* reserved */
	uint32_t	magic;		/* Magic number */
	uint32_t	res5;
};

#define LINUX_ARM64_IMAGE_MAGIC	0x644d5241

static int booti_setup(bootm_headers_t *images)
{
	struct Image_header *ih;
	uint64_t dst;
658
	uint64_t image_size;
659 660 661 662 663 664 665 666 667 668

	ih = (struct Image_header *)map_sysmem(images->ep, 0);

	if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) {
		puts("Bad Linux ARM64 Image magic!\n");
		return 1;
	}
	
	if (ih->image_size == 0) {
		puts("Image lacks image_size field, assuming 16MiB\n");
669 670 671
		image_size = 16 << 20;
	} else {
		image_size = le64_to_cpu(ih->image_size);
672 673 674 675 676 677
	}

	/*
	 * If we are not at the correct run-time location, set the new
	 * correct location and then move the image there.
	 */
678
	dst = gd->bd->bi_dram[0].start + le64_to_cpu(ih->text_offset);
679 680 681

	unmap_sysmem(ih);

682 683 684 685 686 687 688
	if (images->ep != dst) {
		void *src;

		debug("Moving Image from 0x%lx to 0x%llx\n", images->ep, dst);

		src = (void *)images->ep;
		images->ep = dst;
689
		memmove((void *)dst, src, image_size);
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
	}

	return 0;
}

/*
 * Image booting support
 */
static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc,
			char * const argv[], bootm_headers_t *images)
{
	int ret;
	struct Image_header *ih;

	ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
			      images, 1);

	/* Setup Linux kernel Image entry point */
	if (!argc) {
		images->ep = load_addr;
		debug("*  kernel: default image load address = 0x%08lx\n",
				load_addr);
	} else {
		images->ep = simple_strtoul(argv[0], NULL, 16);
		debug("*  kernel: cmdline image address = 0x%08lx\n",
			images->ep);
	}

	ret = booti_setup(images);
	if (ret != 0)
		return 1;

	ih = (struct Image_header *)map_sysmem(images->ep, 0);

	lmb_reserve(&images->lmb, images->ep, le32_to_cpu(ih->image_size));

726 727
	unmap_sysmem(ih);

728 729 730 731
	/*
	 * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
	 * have a header that provide this informaiton.
	 */
732
	if (bootm_find_images(flag, argc, argv))
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
		return 1;

	return 0;
}

int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int ret;

	/* Consume 'booti' */
	argc--; argv++;

	if (booti_start(cmdtp, flag, argc, argv, &images))
		return 1;

	/*
	 * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
	 * disable interrupts ourselves
	 */
	bootm_disable_interrupts();

	images.os.os = IH_OS_LINUX;
	ret = do_bootm_states(cmdtp, flag, argc, argv,
			      BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
			      BOOTM_STATE_OS_GO,
			      &images, 1);

	return ret;
}

#ifdef CONFIG_SYS_LONGHELP
static char booti_help_text[] =
	"[addr [initrd[:size]] [fdt]]\n"
766
	"    - boot arm64 Linux Image stored in memory\n"
767
	"\tThe argument 'initrd' is optional and specifies the address\n"
768 769
	"\tof an initrd in memory. The optional parameter ':size' allows\n"
	"\tspecifying the size of a RAW initrd.\n"
770
#if defined(CONFIG_OF_LIBFDT)
771 772 773 774
	"\tSince booting a Linux kernel requires a flat device-tree, a\n"
	"\tthird argument providing the address of the device-tree blob\n"
	"\tis required. To boot a kernel with a device-tree blob but\n"
	"\twithout an initrd image, use a '-' for the initrd argument.\n"
775 776 777 778 779 780 781 782 783
#endif
	"";
#endif

U_BOOT_CMD(
	booti,	CONFIG_SYS_MAXARGS,	1,	do_booti,
	"boot arm64 Linux Image image from memory", booti_help_text
);
#endif	/* CONFIG_CMD_BOOTI */