xref: /rk3399_rockchip-uboot/common/image.c (revision fff888a1997ff7de9b29e24050fc4a0fd403ba16)
1 /*
2  * (C) Copyright 2008 Semihalf
3  *
4  * (C) Copyright 2000-2006
5  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25 
26 #define DEBUG
27 
28 #ifndef USE_HOSTCC
29 #include <common.h>
30 #include <watchdog.h>
31 
32 #ifdef CONFIG_SHOW_BOOT_PROGRESS
33 #include <status_led.h>
34 #endif
35 
36 #ifdef CONFIG_HAS_DATAFLASH
37 #include <dataflash.h>
38 #endif
39 
40 #ifdef CONFIG_LOGBUFFER
41 #include <logbuff.h>
42 #endif
43 
44 #if defined(CONFIG_FIT)
45 #include <fdt.h>
46 #include <libfdt.h>
47 #include <fdt_support.h>
48 #endif
49 
50 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
51 
52 #ifdef CONFIG_CMD_BDI
53 extern int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
54 #endif
55 
56 DECLARE_GLOBAL_DATA_PTR;
57 #else
58 #include "mkimage.h"
59 #endif /* USE_HOSTCC*/
60 
61 #include <image.h>
62 
63 unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
64 
65 int image_check_hcrc (image_header_t *hdr)
66 {
67 	ulong hcrc;
68 	ulong len = image_get_header_size ();
69 	image_header_t header;
70 
71 	/* Copy header so we can blank CRC field for re-calculation */
72 	memmove (&header, (char *)hdr, image_get_header_size ());
73 	image_set_hcrc (&header, 0);
74 
75 	hcrc = crc32 (0, (unsigned char *)&header, len);
76 
77 	return (hcrc == image_get_hcrc (hdr));
78 }
79 
80 int image_check_dcrc (image_header_t *hdr)
81 {
82 	ulong data = image_get_data (hdr);
83 	ulong len = image_get_data_size (hdr);
84 	ulong dcrc = crc32 (0, (unsigned char *)data, len);
85 
86 	return (dcrc == image_get_dcrc (hdr));
87 }
88 
89 #ifndef USE_HOSTCC
90 int image_check_dcrc_wd (image_header_t *hdr, ulong chunksz)
91 {
92 	ulong dcrc = 0;
93 	ulong len = image_get_data_size (hdr);
94 	ulong data = image_get_data (hdr);
95 
96 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
97 	ulong cdata = data;
98 	ulong edata = cdata + len;
99 
100 	while (cdata < edata) {
101 		ulong chunk = edata - cdata;
102 
103 		if (chunk > chunksz)
104 			chunk = chunksz;
105 		dcrc = crc32 (dcrc, (unsigned char *)cdata, chunk);
106 		cdata += chunk;
107 
108 		WATCHDOG_RESET ();
109 	}
110 #else
111 	dcrc = crc32 (0, (unsigned char *)data, len);
112 #endif
113 
114 	return (dcrc == image_get_dcrc (hdr));
115 }
116 
117 int getenv_verify (void)
118 {
119 	char *s = getenv ("verify");
120 	return (s && (*s == 'n')) ? 0 : 1;
121 }
122 
123 void memmove_wd (void *to, void *from, size_t len, ulong chunksz)
124 {
125 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
126 	while (len > 0) {
127 		size_t tail = (len > chunksz) ? chunksz : len;
128 		WATCHDOG_RESET ();
129 		memmove (to, from, tail);
130 		to += tail;
131 		from += tail;
132 		len -= tail;
133 	}
134 #else	/* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
135 	memmove (to, from, len);
136 #endif	/* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
137 }
138 #endif /* USE_HOSTCC */
139 
140 /**
141  * image_multi_count - get component (sub-image) count
142  * @hdr: pointer to the header of the multi component image
143  *
144  * image_multi_count() returns number of components in a multi
145  * component image.
146  *
147  * Note: no checking of the image type is done, caller must pass
148  * a valid multi component image.
149  *
150  * returns:
151  *     number of components
152  */
153 ulong image_multi_count (image_header_t *hdr)
154 {
155 	ulong i, count = 0;
156 	ulong *size;
157 
158 	/* get start of the image payload, which in case of multi
159 	 * component images that points to a table of component sizes */
160 	size = (ulong *)image_get_data (hdr);
161 
162 	/* count non empty slots */
163 	for (i = 0; size[i]; ++i)
164 		count++;
165 
166 	return count;
167 }
168 
169 /**
170  * image_multi_getimg - get component data address and size
171  * @hdr: pointer to the header of the multi component image
172  * @idx: index of the requested component
173  * @data: pointer to a ulong variable, will hold component data address
174  * @len: pointer to a ulong variable, will hold component size
175  *
176  * image_multi_getimg() returns size and data address for the requested
177  * component in a multi component image.
178  *
179  * Note: no checking of the image type is done, caller must pass
180  * a valid multi component image.
181  *
182  * returns:
183  *     data address and size of the component, if idx is valid
184  *     0 in data and len, if idx is out of range
185  */
186 void image_multi_getimg (image_header_t *hdr, ulong idx,
187 			ulong *data, ulong *len)
188 {
189 	int i;
190 	ulong *size;
191 	ulong offset, tail, count, img_data;
192 
193 	/* get number of component */
194 	count = image_multi_count (hdr);
195 
196 	/* get start of the image payload, which in case of multi
197 	 * component images that points to a table of component sizes */
198 	size = (ulong *)image_get_data (hdr);
199 
200 	/* get address of the proper component data start, which means
201 	 * skipping sizes table (add 1 for last, null entry) */
202 	img_data = image_get_data (hdr) + (count + 1) * sizeof (ulong);
203 
204 	if (idx < count) {
205 		*len = size[idx];
206 		offset = 0;
207 		tail = 0;
208 
209 		/* go over all indices preceding requested component idx */
210 		for (i = 0; i < idx; i++) {
211 			/* add up i-th component size */
212 			offset += size[i];
213 
214 			/* add up alignment for i-th component */
215 			tail += (4 - size[i] % 4);
216 		}
217 
218 		/* calculate idx-th component data address */
219 		*data = img_data + offset + tail;
220 	} else {
221 		*len = 0;
222 		*data = 0;
223 	}
224 }
225 
226 #ifndef USE_HOSTCC
227 const char* image_get_os_name (uint8_t os)
228 {
229 	const char *name;
230 
231 	switch (os) {
232 	case IH_OS_INVALID:	name = "Invalid OS";		break;
233 	case IH_OS_NETBSD:	name = "NetBSD";		break;
234 	case IH_OS_LINUX:	name = "Linux";			break;
235 	case IH_OS_VXWORKS:	name = "VxWorks";		break;
236 	case IH_OS_QNX:		name = "QNX";			break;
237 	case IH_OS_U_BOOT:	name = "U-Boot";		break;
238 	case IH_OS_RTEMS:	name = "RTEMS";			break;
239 #ifdef CONFIG_ARTOS
240 	case IH_OS_ARTOS:	name = "ARTOS";			break;
241 #endif
242 #ifdef CONFIG_LYNXKDI
243 	case IH_OS_LYNXOS:	name = "LynxOS";		break;
244 #endif
245 	default:		name = "Unknown OS";		break;
246 	}
247 
248 	return name;
249 }
250 
251 const char* image_get_arch_name (uint8_t arch)
252 {
253 	const char *name;
254 
255 	switch (arch) {
256 	case IH_ARCH_INVALID:	name = "Invalid Architecture";	break;
257 	case IH_ARCH_ALPHA:	name = "Alpha";			break;
258 	case IH_ARCH_ARM:	name = "ARM";			break;
259 	case IH_ARCH_AVR32:	name = "AVR32";			break;
260 	case IH_ARCH_BLACKFIN:	name = "Blackfin";		break;
261 	case IH_ARCH_I386:	name = "Intel x86";		break;
262 	case IH_ARCH_IA64:	name = "IA64";			break;
263 	case IH_ARCH_M68K:	name = "M68K"; 			break;
264 	case IH_ARCH_MICROBLAZE:name = "Microblaze"; 		break;
265 	case IH_ARCH_MIPS64:	name = "MIPS 64 Bit";		break;
266 	case IH_ARCH_MIPS:	name = "MIPS";			break;
267 	case IH_ARCH_NIOS2:	name = "Nios-II";		break;
268 	case IH_ARCH_NIOS:	name = "Nios";			break;
269 	case IH_ARCH_PPC:	name = "PowerPC";		break;
270 	case IH_ARCH_S390:	name = "IBM S390";		break;
271 	case IH_ARCH_SH:	name = "SuperH";		break;
272 	case IH_ARCH_SPARC64:	name = "SPARC 64 Bit";		break;
273 	case IH_ARCH_SPARC:	name = "SPARC";			break;
274 	default:		name = "Unknown Architecture";	break;
275 	}
276 
277 	return name;
278 }
279 
280 const char* image_get_type_name (uint8_t type)
281 {
282 	const char *name;
283 
284 	switch (type) {
285 	case IH_TYPE_INVALID:	name = "Invalid Image";		break;
286 	case IH_TYPE_STANDALONE:name = "Standalone Program";	break;
287 	case IH_TYPE_KERNEL:	name = "Kernel Image";		break;
288 	case IH_TYPE_RAMDISK:	name = "RAMDisk Image";		break;
289 	case IH_TYPE_MULTI:	name = "Multi-File Image";	break;
290 	case IH_TYPE_FIRMWARE:	name = "Firmware";		break;
291 	case IH_TYPE_SCRIPT:	name = "Script";		break;
292 	case IH_TYPE_FLATDT:	name = "Flat Device Tree";	break;
293 	default:		name = "Unknown Image";		break;
294 	}
295 
296 	return name;
297 }
298 
299 const char* image_get_comp_name (uint8_t comp)
300 {
301 	const char *name;
302 
303 	switch (comp) {
304 	case IH_COMP_NONE:	name = "uncompressed";		break;
305 	case IH_COMP_GZIP:	name = "gzip compressed";	break;
306 	case IH_COMP_BZIP2:	name = "bzip2 compressed";	break;
307 	default:		name = "unknown compression";	break;
308 	}
309 
310 	return name;
311 }
312 
313 /**
314  * gen_image_get_format - get image format type
315  * @img_addr: image start address
316  *
317  * gen_image_get_format() checks whether provided address points to a valid
318  * legacy or FIT image.
319  *
320  * returns:
321  *     image format type or IMAGE_FORMAT_INVALID if no image is present
322  */
323 int gen_image_get_format (void *img_addr)
324 {
325 	ulong		format = IMAGE_FORMAT_INVALID;
326 	image_header_t	*hdr;
327 #if defined(CONFIG_FIT)
328 	char		*fit_hdr;
329 #endif
330 
331 	hdr = (image_header_t *)img_addr;
332 	if (image_check_magic(hdr))
333 		format = IMAGE_FORMAT_LEGACY;
334 #if defined(CONFIG_FIT)
335 	else {
336 		fit_hdr = (char *)img_addr;
337 		if (fdt_check_header (fit_hdr) == 0)
338 			format = IMAGE_FORMAT_FIT;
339 	}
340 #endif
341 
342 	return format;
343 }
344 
345 /**
346  * gen_get_image - get image from special storage (if necessary)
347  * @img_addr: image start address
348  *
349  * gen_get_image() checks if provided image start adddress is located
350  * in a dataflash storage. If so, image is moved to a system RAM memory.
351  *
352  * returns:
353  *     image start address after possible relocation from special storage
354  */
355 ulong gen_get_image (ulong img_addr)
356 {
357 	ulong ram_addr, h_size, d_size;
358 
359 	h_size = image_get_header_size ();
360 #if defined(CONFIG_FIT)
361 	if (sizeof(struct fdt_header) > h_size)
362 		h_size = sizeof(struct fdt_header);
363 #endif
364 
365 #ifdef CONFIG_HAS_DATAFLASH
366 	if (addr_dataflash (img_addr)){
367 		ram_addr = CFG_LOAD_ADDR;
368 		debug ("   Reading image header from dataflash address "
369 			"%08lx to RAM address %08lx\n", img_addr, ram_addr);
370 		read_dataflash (img_addr, h_size, (char *)ram_addr);
371 	} else
372 #endif
373 		return img_addr;
374 
375 	ram_addr = img_addr;
376 
377 	switch (gen_image_get_format ((void *)ram_addr)) {
378 	case IMAGE_FORMAT_LEGACY:
379 		d_size = image_get_data_size ((image_header_t *)ram_addr);
380 		debug ("   Legacy format image found at 0x%08lx, size 0x%08lx\n",
381 				ram_addr, d_size);
382 		break;
383 #if defined(CONFIG_FIT)
384 	case IMAGE_FORMAT_FIT:
385 		d_size = fdt_totalsize((void *)ram_addr) - h_size;
386 		debug ("   FIT/FDT format image found at 0x%08lx, size 0x%08lx\n",
387 				ram_addr, d_size);
388 
389 		break;
390 #endif
391 	default:
392 		printf ("   No valid image found at 0x%08lx\n", img_addr);
393 		return ram_addr;
394 	}
395 
396 #ifdef CONFIG_HAS_DATAFLASH
397 	if (addr_dataflash (img_addr)) {
398 		debug ("   Reading image remaining data from dataflash address "
399 			"%08lx to RAM address %08lx\n", img_addr + h_size,
400 			ram_addr + h_size);
401 
402 		read_dataflash (img_addr + h_size, d_size,
403 				(char *)(ram_addr + h_size));
404 	}
405 #endif
406 
407 	return ram_addr;
408 }
409 
410 /**
411  * image_get_ramdisk - get and verify ramdisk image
412  * @cmdtp: command table pointer
413  * @flag: command flag
414  * @argc: command argument count
415  * @argv: command argument list
416  * @rd_addr: ramdisk image start address
417  * @arch: expected ramdisk architecture
418  * @verify: checksum verification flag
419  *
420  * image_get_ramdisk() returns a pointer to the verified ramdisk image
421  * header. Routine receives image start address and expected architecture
422  * flag. Verification done covers data and header integrity and os/type/arch
423  * fields checking.
424  *
425  * If dataflash support is enabled routine checks for dataflash addresses
426  * and handles required dataflash reads.
427  *
428  * returns:
429  *     pointer to a ramdisk image header, if image was found and valid
430  *     otherwise, board is reset
431  */
432 image_header_t* image_get_ramdisk (cmd_tbl_t *cmdtp, int flag,
433 		int argc, char *argv[],
434 		ulong rd_addr, uint8_t arch, int verify)
435 {
436 	image_header_t *rd_hdr;
437 
438 	show_boot_progress (9);
439 
440 	/* copy from dataflash if needed */
441 	rd_addr = gen_get_image (rd_addr);
442 	rd_hdr = (image_header_t *)rd_addr;
443 
444 	if (!image_check_magic (rd_hdr)) {
445 		puts ("Bad Magic Number\n");
446 		show_boot_progress (-10);
447 		do_reset (cmdtp, flag, argc, argv);
448 	}
449 
450 	if (!image_check_hcrc (rd_hdr)) {
451 		puts ("Bad Header Checksum\n");
452 		show_boot_progress (-11);
453 		do_reset (cmdtp, flag, argc, argv);
454 	}
455 
456 	show_boot_progress (10);
457 	print_image_hdr (rd_hdr);
458 
459 	if (verify) {
460 		puts("   Verifying Checksum ... ");
461 		if (!image_check_dcrc_wd (rd_hdr, CHUNKSZ)) {
462 			puts ("Bad Data CRC\n");
463 			show_boot_progress (-12);
464 			do_reset (cmdtp, flag, argc, argv);
465 		}
466 		puts("OK\n");
467 	}
468 
469 	show_boot_progress (11);
470 
471 	if (!image_check_os (rd_hdr, IH_OS_LINUX) ||
472 	    !image_check_arch (rd_hdr, arch) ||
473 	    !image_check_type (rd_hdr, IH_TYPE_RAMDISK)) {
474 		printf ("No Linux %s Ramdisk Image\n",
475 				image_get_arch_name(arch));
476 		show_boot_progress (-13);
477 		do_reset (cmdtp, flag, argc, argv);
478 	}
479 
480 	return rd_hdr;
481 }
482 
483 /**
484  * get_ramdisk - main ramdisk handling routine
485  * @cmdtp: command table pointer
486  * @flag: command flag
487  * @argc: command argument count
488  * @argv: command argument list
489  * @hdr: pointer to the posiibly multi componet kernel image
490  * @verify: checksum verification flag
491  * @arch: expected ramdisk architecture
492  * @rd_start: pointer to a ulong variable, will hold ramdisk start address
493  * @rd_end: pointer to a ulong variable, will hold ramdisk end
494  *
495  * get_ramdisk() is responsible for finding a valid ramdisk image.
496  * Curently supported are the following ramdisk sources:
497  *      - multicomponent kernel/ramdisk image,
498  *      - commandline provided address of decicated ramdisk image.
499  *
500  * returns:
501  *     rd_start and rd_end are set to ramdisk start/end addresses if
502  *     ramdisk image is found and valid
503  *     rd_start and rd_end are set to 0 if no ramdisk exists
504  *     board is reset if ramdisk image is found but corrupted
505  */
506 void get_ramdisk (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
507 		image_header_t *hdr, int verify, uint8_t arch,
508 		ulong *rd_start, ulong *rd_end)
509 {
510 	ulong rd_addr;
511 	ulong rd_data, rd_len;
512 	image_header_t *rd_hdr;
513 
514 	if (argc >= 3) {
515 		/*
516 		 * Look for a '-' which indicates to ignore the
517 		 * ramdisk argument
518 		 */
519 		if (strcmp(argv[2], "-") ==  0) {
520 			debug ("## Skipping init Ramdisk\n");
521 			rd_len = rd_data = 0;
522 		} else {
523 			/*
524 			 * Check if there is an initrd image at the
525 			 * address provided in the second bootm argument
526 			 */
527 			rd_addr = simple_strtoul (argv[2], NULL, 16);
528 			printf ("## Loading init Ramdisk Image at %08lx ...\n",
529 					rd_addr);
530 
531 			rd_hdr = image_get_ramdisk (cmdtp, flag, argc, argv,
532 						rd_addr, arch, verify);
533 
534 			rd_data = image_get_data (rd_hdr);
535 			rd_len = image_get_data_size (rd_hdr);
536 
537 #if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
538 			/*
539 			 *we need to copy the ramdisk to SRAM to let Linux boot
540 			 */
541 			memmove ((void *)image_get_load (rd_hdr),
542 					(uchar *)rd_data, rd_len);
543 
544 			rd_data = image_get_load (rd_hdr);
545 #endif /* CONFIG_B2 || CONFIG_EVB4510 || CONFIG_ARMADILLO */
546 		}
547 
548 	} else if (image_check_type (hdr, IH_TYPE_MULTI)) {
549 		/*
550 		 * Now check if we have a multifile image
551 		 * Get second entry data start address and len
552 		 */
553 		show_boot_progress (13);
554 		printf ("## Loading init Ramdisk from multi component "
555 				"Image at %08lx ...\n", (ulong)hdr);
556 		image_multi_getimg (hdr, 1, &rd_data, &rd_len);
557 	} else {
558 		/*
559 		 * no initrd image
560 		 */
561 		show_boot_progress (14);
562 		rd_len = rd_data = 0;
563 	}
564 
565 	if (!rd_data) {
566 		debug ("## No init Ramdisk\n");
567 		*rd_start = 0;
568 		*rd_end = 0;
569 	} else {
570 		*rd_start = rd_data;
571 		*rd_end = rd_data + rd_len;
572 	}
573 	debug ("   ramdisk start = 0x%08lx, ramdisk end = 0x%08lx\n",
574 			*rd_start, *rd_end);
575 }
576 
577 #if defined(CONFIG_PPC) || defined(CONFIG_M68K)
578 /**
579  * ramdisk_high - relocate init ramdisk
580  * @rd_data: ramdisk data start address
581  * @rd_len: ramdisk data length
582  * @kbd: kernel board info copy (within BOOTMAPSZ boundary)
583  * @sp_limit: stack pointer limit (including BOOTMAPSZ)
584  * @sp: current stack pointer
585  * @initrd_start: pointer to a ulong variable, will hold final init ramdisk
586  *      start address (after possible relocation)
587  * @initrd_end: pointer to a ulong variable, will hold final init ramdisk
588  *      end address (after possible relocation)
589  *
590  * ramdisk_high() takes a relocation hint from "initrd_high" environement
591  * variable and if requested ramdisk data is moved to a specified location.
592  *
593  * returns:
594  *     - initrd_start and initrd_end are set to final (after relocation) ramdisk
595  *     start/end addresses if ramdisk image start and len were provided
596  *     otherwise set initrd_start and initrd_end set to zeros
597  *     - returns new allc_current, next free address below BOOTMAPSZ
598  */
599 ulong ramdisk_high (ulong alloc_current, ulong rd_data, ulong rd_len,
600 		bd_t *kbd, ulong sp_limit, ulong sp,
601 		ulong *initrd_start, ulong *initrd_end)
602 {
603 	char	*s;
604 	ulong	initrd_high;
605 	int	initrd_copy_to_ram = 1;
606 	ulong	new_alloc_current = alloc_current;
607 
608 	if ((s = getenv ("initrd_high")) != NULL) {
609 		/* a value of "no" or a similar string will act like 0,
610 		 * turning the "load high" feature off. This is intentional.
611 		 */
612 		initrd_high = simple_strtoul (s, NULL, 16);
613 		if (initrd_high == ~0)
614 			initrd_copy_to_ram = 0;
615 	} else {
616 		/* not set, no restrictions to load high */
617 		initrd_high = ~0;
618 	}
619 
620 #ifdef CONFIG_LOGBUFFER
621 	/* Prevent initrd from overwriting logbuffer */
622 	if (initrd_high < (kbd->bi_memsize - LOGBUFF_LEN - LOGBUFF_OVERHEAD))
623 		initrd_high = kbd->bi_memsize - LOGBUFF_LEN - LOGBUFF_OVERHEAD;
624 	debug ("## Logbuffer at 0x%08lx ", kbd->bi_memsize - LOGBUFF_LEN);
625 #endif
626 	debug ("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
627 			initrd_high, initrd_copy_to_ram);
628 
629 	if (rd_data) {
630 		if (!initrd_copy_to_ram) {	/* zero-copy ramdisk support */
631 			debug ("   in-place initrd\n");
632 			*initrd_start = rd_data;
633 			*initrd_end = rd_data + rd_len;
634 		} else {
635 			new_alloc_current = alloc_current - rd_len;
636 			*initrd_start  = new_alloc_current;
637 			*initrd_start &= ~(4096 - 1);	/* align on page */
638 
639 			if (initrd_high) {
640 				ulong nsp;
641 
642 				/*
643 				 * the inital ramdisk does not need to be within
644 				 * CFG_BOOTMAPSZ as it is not accessed until after
645 				 * the mm system is initialised.
646 				 *
647 				 * do the stack bottom calculation again and see if
648 				 * the initrd will fit just below the monitor stack
649 				 * bottom without overwriting the area allocated
650 				 * for command line args and board info.
651 				 */
652 				nsp = sp;
653 				nsp -= 2048;		/* just to be sure */
654 				nsp &= ~0xF;
655 
656 				if (nsp > initrd_high)	/* limit as specified */
657 					nsp = initrd_high;
658 
659 				nsp -= rd_len;
660 				nsp &= ~(4096 - 1);	/* align on page */
661 
662 				if (nsp >= sp_limit) {
663 					*initrd_start = nsp;
664 					new_alloc_current = alloc_current;
665 				}
666 			}
667 
668 			show_boot_progress (12);
669 
670 			*initrd_end = *initrd_start + rd_len;
671 			printf ("   Loading Ramdisk to %08lx, end %08lx ... ",
672 					*initrd_start, *initrd_end);
673 
674 			memmove_wd((void *)*initrd_start,
675 					(void *)rd_data, rd_len, CHUNKSZ);
676 
677 			puts ("OK\n");
678 		}
679 	} else {
680 		*initrd_start = 0;
681 		*initrd_end = 0;
682 	}
683 	debug ("   ramdisk load start = 0x%08lx, ramdisk load end = 0x%08lx\n",
684 			*initrd_start, *initrd_end);
685 
686 	return new_alloc_current;
687 }
688 
689 /**
690  * get_boot_sp_limit - calculate stack pointer limit
691  * @sp: current stack pointer
692  *
693  * get_boot_sp_limit() takes current stack pointer adrress and calculates
694  * stack pointer limit, below which kernel boot data (cmdline, board info,
695  * etc.) will be allocated.
696  *
697  * returns:
698  *     stack pointer limit
699  */
700 ulong get_boot_sp_limit(ulong sp)
701 {
702 	ulong sp_limit = sp;
703 
704 	sp_limit -= 2048;	/* just to be sure */
705 
706 	/* make sure sp_limit is within kernel mapped space */
707 	if (sp_limit > CFG_BOOTMAPSZ)
708 		sp_limit = CFG_BOOTMAPSZ;
709 	sp_limit &= ~0xF;
710 
711 	return sp_limit;
712 }
713 
714 /**
715  * get_boot_cmdline - allocate and initialize kernel cmdline
716  * @alloc_current: current boot allocation address (counting down
717  *      from sp_limit)
718  * @cmd_start: pointer to a ulong variable, will hold cmdline start
719  * @cmd_end: pointer to a ulong variable, will hold cmdline end
720  *
721  * get_boot_cmdline() allocates space for kernel command line below
722  * provided alloc_current address. If "bootargs" U-boot environemnt
723  * variable is present its contents is copied to allocated kernel
724  * command line.
725  *
726  * returns:
727  *     alloc_current after cmdline allocation
728  */
729 ulong get_boot_cmdline (ulong alloc_current, ulong *cmd_start, ulong *cmd_end)
730 {
731 	char *cmdline;
732 	char *s;
733 
734 	cmdline = (char *)((alloc_current - CFG_BARGSIZE) & ~0xF);
735 
736 	if ((s = getenv("bootargs")) == NULL)
737 		s = "";
738 
739 	strcpy(cmdline, s);
740 
741 	*cmd_start = (ulong) & cmdline[0];
742 	*cmd_end = *cmd_start + strlen(cmdline);
743 
744 	debug ("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end);
745 
746 	return (ulong)cmdline;
747 }
748 
749 /**
750  * get_boot_kbd - allocate and initialize kernel copy of board info
751  * @alloc_current: current boot allocation address (counting down
752  *      from sp_limit)
753  * @kbd: double pointer to board info data
754  *
755  * get_boot_kbd() - allocates space for kernel copy of board info data.
756  * Space is allocated below provided alloc_current address and kernel
757  * board info is initialized with the current u-boot board info data.
758  *
759  * returns:
760  *     alloc_current after kbd allocation
761  */
762 ulong get_boot_kbd (ulong alloc_current, bd_t **kbd)
763 {
764 	*kbd = (bd_t *) (((ulong)alloc_current - sizeof(bd_t)) & ~0xF);
765 	**kbd = *(gd->bd);
766 
767 	debug ("## kernel board info at 0x%08lx\n", (ulong)*kbd);
768 
769 #if defined(DEBUG) && defined(CONFIG_CMD_BDI)
770 	do_bdinfo(NULL, 0, 0, NULL);
771 #endif
772 
773 	return (ulong)*kbd;
774 }
775 #endif /* CONFIG_PPC || CONFIG_M68K */
776 
777 #endif /* USE_HOSTCC */
778