xref: /openbmc/linux/arch/powerpc/boot/main.c (revision 30d8caf7c625203b295a78f143820cdc3124830b)
194b212c2SPaul Mackerras /*
294b212c2SPaul Mackerras  * Copyright (C) Paul Mackerras 1997.
394b212c2SPaul Mackerras  *
494b212c2SPaul Mackerras  * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
594b212c2SPaul Mackerras  *
694b212c2SPaul Mackerras  * This program is free software; you can redistribute it and/or
794b212c2SPaul Mackerras  * modify it under the terms of the GNU General Public License
894b212c2SPaul Mackerras  * as published by the Free Software Foundation; either version
994b212c2SPaul Mackerras  * 2 of the License, or (at your option) any later version.
1094b212c2SPaul Mackerras  */
1194b212c2SPaul Mackerras #include <stdarg.h>
1294b212c2SPaul Mackerras #include <stddef.h>
1394b212c2SPaul Mackerras #include "elf.h"
1494b212c2SPaul Mackerras #include "page.h"
1594b212c2SPaul Mackerras #include "string.h"
1694b212c2SPaul Mackerras #include "stdio.h"
1794b212c2SPaul Mackerras #include "prom.h"
1894b212c2SPaul Mackerras #include "zlib.h"
1994b212c2SPaul Mackerras 
2094b212c2SPaul Mackerras extern void flush_cache(void *, unsigned long);
2194b212c2SPaul Mackerras 
2294b212c2SPaul Mackerras 
2394b212c2SPaul Mackerras /* Value picked to match that used by yaboot */
2466a45dd3SPaul Mackerras #define PROG_START	0x01400000	/* only used on 64-bit systems */
2566a45dd3SPaul Mackerras #define RAM_END		(512<<20)	/* Fixme: use OF */
2694b212c2SPaul Mackerras #define	ONE_MB		0x100000
2794b212c2SPaul Mackerras 
2894b212c2SPaul Mackerras extern char _start[];
2994b212c2SPaul Mackerras extern char __bss_start[];
3094b212c2SPaul Mackerras extern char _end[];
3194b212c2SPaul Mackerras extern char _vmlinux_start[];
3294b212c2SPaul Mackerras extern char _vmlinux_end[];
3394b212c2SPaul Mackerras extern char _initrd_start[];
3494b212c2SPaul Mackerras extern char _initrd_end[];
3594b212c2SPaul Mackerras 
36*30d8caf7Smostrows@watson.ibm.com /* A buffer that may be edited by tools operating on a zImage binary so as to
37*30d8caf7Smostrows@watson.ibm.com  * edit the command line passed to vmlinux (by setting /chosen/bootargs).
38*30d8caf7Smostrows@watson.ibm.com  * The buffer is put in it's own section so that tools may locate it easier.
39*30d8caf7Smostrows@watson.ibm.com  */
40*30d8caf7Smostrows@watson.ibm.com static char builtin_cmdline[512]
41*30d8caf7Smostrows@watson.ibm.com 	__attribute__((section("__builtin_cmdline")));
42*30d8caf7Smostrows@watson.ibm.com 
43*30d8caf7Smostrows@watson.ibm.com 
4494b212c2SPaul Mackerras struct addr_range {
4594b212c2SPaul Mackerras 	unsigned long addr;
4694b212c2SPaul Mackerras 	unsigned long size;
4794b212c2SPaul Mackerras 	unsigned long memsize;
4894b212c2SPaul Mackerras };
4994b212c2SPaul Mackerras static struct addr_range vmlinux;
5094b212c2SPaul Mackerras static struct addr_range vmlinuz;
5194b212c2SPaul Mackerras static struct addr_range initrd;
5294b212c2SPaul Mackerras 
5394b212c2SPaul Mackerras static unsigned long elfoffset;
5494b212c2SPaul Mackerras 
5594b212c2SPaul Mackerras static char scratch[46912];	/* scratch space for gunzip, from zlib_inflate_workspacesize() */
5694b212c2SPaul Mackerras static char elfheader[256];
5794b212c2SPaul Mackerras 
5894b212c2SPaul Mackerras 
5994b212c2SPaul Mackerras typedef void (*kernel_entry_t)( unsigned long,
6094b212c2SPaul Mackerras                                 unsigned long,
6194b212c2SPaul Mackerras                                 void *,
6294b212c2SPaul Mackerras 				void *);
6394b212c2SPaul Mackerras 
6494b212c2SPaul Mackerras 
6594b212c2SPaul Mackerras #undef DEBUG
6694b212c2SPaul Mackerras 
6794b212c2SPaul Mackerras static unsigned long claim_base;
6894b212c2SPaul Mackerras 
6994b212c2SPaul Mackerras #define HEAD_CRC	2
7094b212c2SPaul Mackerras #define EXTRA_FIELD	4
7194b212c2SPaul Mackerras #define ORIG_NAME	8
7294b212c2SPaul Mackerras #define COMMENT		0x10
7394b212c2SPaul Mackerras #define RESERVED	0xe0
7494b212c2SPaul Mackerras 
7594b212c2SPaul Mackerras static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
7694b212c2SPaul Mackerras {
7794b212c2SPaul Mackerras 	z_stream s;
7894b212c2SPaul Mackerras 	int r, i, flags;
7994b212c2SPaul Mackerras 
8094b212c2SPaul Mackerras 	/* skip header */
8194b212c2SPaul Mackerras 	i = 10;
8294b212c2SPaul Mackerras 	flags = src[3];
8394b212c2SPaul Mackerras 	if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
8494b212c2SPaul Mackerras 		printf("bad gzipped data\n\r");
8594b212c2SPaul Mackerras 		exit();
8694b212c2SPaul Mackerras 	}
8794b212c2SPaul Mackerras 	if ((flags & EXTRA_FIELD) != 0)
8894b212c2SPaul Mackerras 		i = 12 + src[10] + (src[11] << 8);
8994b212c2SPaul Mackerras 	if ((flags & ORIG_NAME) != 0)
9094b212c2SPaul Mackerras 		while (src[i++] != 0)
9194b212c2SPaul Mackerras 			;
9294b212c2SPaul Mackerras 	if ((flags & COMMENT) != 0)
9394b212c2SPaul Mackerras 		while (src[i++] != 0)
9494b212c2SPaul Mackerras 			;
9594b212c2SPaul Mackerras 	if ((flags & HEAD_CRC) != 0)
9694b212c2SPaul Mackerras 		i += 2;
9794b212c2SPaul Mackerras 	if (i >= *lenp) {
9894b212c2SPaul Mackerras 		printf("gunzip: ran out of data in header\n\r");
9994b212c2SPaul Mackerras 		exit();
10094b212c2SPaul Mackerras 	}
10194b212c2SPaul Mackerras 
10294b212c2SPaul Mackerras 	if (zlib_inflate_workspacesize() > sizeof(scratch)) {
10394b212c2SPaul Mackerras 		printf("gunzip needs more mem\n");
10494b212c2SPaul Mackerras 		exit();
10594b212c2SPaul Mackerras 	}
10694b212c2SPaul Mackerras 	memset(&s, 0, sizeof(s));
10794b212c2SPaul Mackerras 	s.workspace = scratch;
10894b212c2SPaul Mackerras 	r = zlib_inflateInit2(&s, -MAX_WBITS);
10994b212c2SPaul Mackerras 	if (r != Z_OK) {
11094b212c2SPaul Mackerras 		printf("inflateInit2 returned %d\n\r", r);
11194b212c2SPaul Mackerras 		exit();
11294b212c2SPaul Mackerras 	}
11394b212c2SPaul Mackerras 	s.next_in = src + i;
11494b212c2SPaul Mackerras 	s.avail_in = *lenp - i;
11594b212c2SPaul Mackerras 	s.next_out = dst;
11694b212c2SPaul Mackerras 	s.avail_out = dstlen;
11794b212c2SPaul Mackerras 	r = zlib_inflate(&s, Z_FULL_FLUSH);
11894b212c2SPaul Mackerras 	if (r != Z_OK && r != Z_STREAM_END) {
11994b212c2SPaul Mackerras 		printf("inflate returned %d msg: %s\n\r", r, s.msg);
12094b212c2SPaul Mackerras 		exit();
12194b212c2SPaul Mackerras 	}
12294b212c2SPaul Mackerras 	*lenp = s.next_out - (unsigned char *) dst;
12394b212c2SPaul Mackerras 	zlib_inflateEnd(&s);
12494b212c2SPaul Mackerras }
12594b212c2SPaul Mackerras 
12694b212c2SPaul Mackerras static unsigned long try_claim(unsigned long size)
12794b212c2SPaul Mackerras {
12894b212c2SPaul Mackerras 	unsigned long addr = 0;
12994b212c2SPaul Mackerras 
13094b212c2SPaul Mackerras 	for(; claim_base < RAM_END; claim_base += ONE_MB) {
13194b212c2SPaul Mackerras #ifdef DEBUG
13294b212c2SPaul Mackerras 		printf("    trying: 0x%08lx\n\r", claim_base);
13394b212c2SPaul Mackerras #endif
13494b212c2SPaul Mackerras 		addr = (unsigned long)claim(claim_base, size, 0);
13594b212c2SPaul Mackerras 		if ((void *)addr != (void *)-1)
13694b212c2SPaul Mackerras 			break;
13794b212c2SPaul Mackerras 	}
13894b212c2SPaul Mackerras 	if (addr == 0)
13994b212c2SPaul Mackerras 		return 0;
14094b212c2SPaul Mackerras 	claim_base = PAGE_ALIGN(claim_base + size);
14194b212c2SPaul Mackerras 	return addr;
14294b212c2SPaul Mackerras }
14394b212c2SPaul Mackerras 
14494b212c2SPaul Mackerras static int is_elf64(void *hdr)
14594b212c2SPaul Mackerras {
14694b212c2SPaul Mackerras 	Elf64_Ehdr *elf64 = hdr;
14794b212c2SPaul Mackerras 	Elf64_Phdr *elf64ph;
14894b212c2SPaul Mackerras 	unsigned int i;
14994b212c2SPaul Mackerras 
15094b212c2SPaul Mackerras 	if (!(elf64->e_ident[EI_MAG0]  == ELFMAG0	&&
15194b212c2SPaul Mackerras 	      elf64->e_ident[EI_MAG1]  == ELFMAG1	&&
15294b212c2SPaul Mackerras 	      elf64->e_ident[EI_MAG2]  == ELFMAG2	&&
15394b212c2SPaul Mackerras 	      elf64->e_ident[EI_MAG3]  == ELFMAG3	&&
15494b212c2SPaul Mackerras 	      elf64->e_ident[EI_CLASS] == ELFCLASS64	&&
15594b212c2SPaul Mackerras 	      elf64->e_ident[EI_DATA]  == ELFDATA2MSB	&&
15694b212c2SPaul Mackerras 	      elf64->e_type            == ET_EXEC	&&
15794b212c2SPaul Mackerras 	      elf64->e_machine         == EM_PPC64))
15894b212c2SPaul Mackerras 		return 0;
15994b212c2SPaul Mackerras 
16094b212c2SPaul Mackerras 	elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
16194b212c2SPaul Mackerras 				 (unsigned long)elf64->e_phoff);
16294b212c2SPaul Mackerras 	for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
163158daa4cSOlaf Hering 		if (elf64ph->p_type == PT_LOAD)
16494b212c2SPaul Mackerras 			break;
16594b212c2SPaul Mackerras 	if (i >= (unsigned int)elf64->e_phnum)
16694b212c2SPaul Mackerras 		return 0;
16794b212c2SPaul Mackerras 
16894b212c2SPaul Mackerras 	elfoffset = (unsigned long)elf64ph->p_offset;
16994b212c2SPaul Mackerras 	vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
17094b212c2SPaul Mackerras 	vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
17166a45dd3SPaul Mackerras 
17266a45dd3SPaul Mackerras #if defined(PROG_START)
17366a45dd3SPaul Mackerras 	/*
17466a45dd3SPaul Mackerras 	 * Maintain a "magic" minimum address. This keeps some older
17566a45dd3SPaul Mackerras 	 * firmware platforms running.
17666a45dd3SPaul Mackerras 	 */
17766a45dd3SPaul Mackerras 
17866a45dd3SPaul Mackerras 	if (claim_base < PROG_START)
17966a45dd3SPaul Mackerras 		claim_base = PROG_START;
18066a45dd3SPaul Mackerras #endif
18166a45dd3SPaul Mackerras 
18294b212c2SPaul Mackerras 	return 1;
18394b212c2SPaul Mackerras }
18494b212c2SPaul Mackerras 
18594b212c2SPaul Mackerras static int is_elf32(void *hdr)
18694b212c2SPaul Mackerras {
18794b212c2SPaul Mackerras 	Elf32_Ehdr *elf32 = hdr;
18894b212c2SPaul Mackerras 	Elf32_Phdr *elf32ph;
18994b212c2SPaul Mackerras 	unsigned int i;
19094b212c2SPaul Mackerras 
19194b212c2SPaul Mackerras 	if (!(elf32->e_ident[EI_MAG0]  == ELFMAG0	&&
19294b212c2SPaul Mackerras 	      elf32->e_ident[EI_MAG1]  == ELFMAG1	&&
19394b212c2SPaul Mackerras 	      elf32->e_ident[EI_MAG2]  == ELFMAG2	&&
19494b212c2SPaul Mackerras 	      elf32->e_ident[EI_MAG3]  == ELFMAG3	&&
19594b212c2SPaul Mackerras 	      elf32->e_ident[EI_CLASS] == ELFCLASS32	&&
19694b212c2SPaul Mackerras 	      elf32->e_ident[EI_DATA]  == ELFDATA2MSB	&&
19794b212c2SPaul Mackerras 	      elf32->e_type            == ET_EXEC	&&
19894b212c2SPaul Mackerras 	      elf32->e_machine         == EM_PPC))
19994b212c2SPaul Mackerras 		return 0;
20094b212c2SPaul Mackerras 
20194b212c2SPaul Mackerras 	elf32 = (Elf32_Ehdr *)elfheader;
20294b212c2SPaul Mackerras 	elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
20394b212c2SPaul Mackerras 	for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
204158daa4cSOlaf Hering 		if (elf32ph->p_type == PT_LOAD)
20594b212c2SPaul Mackerras 			break;
20694b212c2SPaul Mackerras 	if (i >= elf32->e_phnum)
20794b212c2SPaul Mackerras 		return 0;
20894b212c2SPaul Mackerras 
20994b212c2SPaul Mackerras 	elfoffset = elf32ph->p_offset;
21094b212c2SPaul Mackerras 	vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
21194b212c2SPaul Mackerras 	vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
21294b212c2SPaul Mackerras 	return 1;
21394b212c2SPaul Mackerras }
21494b212c2SPaul Mackerras 
215*30d8caf7Smostrows@watson.ibm.com void export_cmdline(void* chosen_handle)
216*30d8caf7Smostrows@watson.ibm.com {
217*30d8caf7Smostrows@watson.ibm.com         int len;
218*30d8caf7Smostrows@watson.ibm.com         char cmdline[2] = { 0, 0 };
219*30d8caf7Smostrows@watson.ibm.com 
220*30d8caf7Smostrows@watson.ibm.com 	if (builtin_cmdline[0] == 0)
221*30d8caf7Smostrows@watson.ibm.com 		return;
222*30d8caf7Smostrows@watson.ibm.com 
223*30d8caf7Smostrows@watson.ibm.com         len = getprop(chosen_handle, "bootargs", cmdline, sizeof(cmdline));
224*30d8caf7Smostrows@watson.ibm.com         if (len > 0 && cmdline[0] != 0)
225*30d8caf7Smostrows@watson.ibm.com 		return;
226*30d8caf7Smostrows@watson.ibm.com 
227*30d8caf7Smostrows@watson.ibm.com 	setprop(chosen_handle, "bootargs", builtin_cmdline,
228*30d8caf7Smostrows@watson.ibm.com 		strlen(builtin_cmdline) + 1);
229*30d8caf7Smostrows@watson.ibm.com }
230*30d8caf7Smostrows@watson.ibm.com 
231*30d8caf7Smostrows@watson.ibm.com 
23294b212c2SPaul Mackerras void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
23394b212c2SPaul Mackerras {
23494b212c2SPaul Mackerras 	int len;
23594b212c2SPaul Mackerras 	kernel_entry_t kernel_entry;
23694b212c2SPaul Mackerras 
23794b212c2SPaul Mackerras 	memset(__bss_start, 0, _end - __bss_start);
23894b212c2SPaul Mackerras 
23994b212c2SPaul Mackerras 	prom = (int (*)(void *)) promptr;
24094b212c2SPaul Mackerras 	chosen_handle = finddevice("/chosen");
24194b212c2SPaul Mackerras 	if (chosen_handle == (void *) -1)
24294b212c2SPaul Mackerras 		exit();
24394b212c2SPaul Mackerras 	if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
24494b212c2SPaul Mackerras 		exit();
24594b212c2SPaul Mackerras 
24694b212c2SPaul Mackerras 	printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
24794b212c2SPaul Mackerras 
24866a45dd3SPaul Mackerras 	/*
24966a45dd3SPaul Mackerras 	 * The first available claim_base must be above the end of the
25066a45dd3SPaul Mackerras 	 * the loaded kernel wrapper file (_start to _end includes the
25166a45dd3SPaul Mackerras 	 * initrd image if it is present) and rounded up to a nice
25266a45dd3SPaul Mackerras 	 * 1 MB boundary for good measure.
25366a45dd3SPaul Mackerras 	 */
25466a45dd3SPaul Mackerras 
25566a45dd3SPaul Mackerras 	claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
25666a45dd3SPaul Mackerras 
25794b212c2SPaul Mackerras 	vmlinuz.addr = (unsigned long)_vmlinux_start;
25894b212c2SPaul Mackerras 	vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
25994b212c2SPaul Mackerras 
26094b212c2SPaul Mackerras 	/* gunzip the ELF header of the kernel */
26194b212c2SPaul Mackerras 	if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
26294b212c2SPaul Mackerras 		len = vmlinuz.size;
26394b212c2SPaul Mackerras 		gunzip(elfheader, sizeof(elfheader),
26494b212c2SPaul Mackerras 				(unsigned char *)vmlinuz.addr, &len);
26594b212c2SPaul Mackerras 	} else
26694b212c2SPaul Mackerras 		memcpy(elfheader, (const void *)vmlinuz.addr, sizeof(elfheader));
26794b212c2SPaul Mackerras 
26894b212c2SPaul Mackerras 	if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
26994b212c2SPaul Mackerras 		printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
27094b212c2SPaul Mackerras 		exit();
27194b212c2SPaul Mackerras 	}
27294b212c2SPaul Mackerras 
27394b212c2SPaul Mackerras 	/* We need to claim the memsize plus the file offset since gzip
27494b212c2SPaul Mackerras 	 * will expand the header (file offset), then the kernel, then
27594b212c2SPaul Mackerras 	 * possible rubbish we don't care about. But the kernel bss must
27694b212c2SPaul Mackerras 	 * be claimed (it will be zero'd by the kernel itself)
27794b212c2SPaul Mackerras 	 */
27894b212c2SPaul Mackerras 	printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
27994b212c2SPaul Mackerras 	vmlinux.addr = try_claim(vmlinux.memsize);
28094b212c2SPaul Mackerras 	if (vmlinux.addr == 0) {
28194b212c2SPaul Mackerras 		printf("Can't allocate memory for kernel image !\n\r");
28294b212c2SPaul Mackerras 		exit();
28394b212c2SPaul Mackerras 	}
28494b212c2SPaul Mackerras 
28594b212c2SPaul Mackerras 	/*
28694b212c2SPaul Mackerras 	 * Now we try to claim memory for the initrd (and copy it there)
28794b212c2SPaul Mackerras 	 */
28894b212c2SPaul Mackerras 	initrd.size = (unsigned long)(_initrd_end - _initrd_start);
28994b212c2SPaul Mackerras 	initrd.memsize = initrd.size;
29094b212c2SPaul Mackerras 	if ( initrd.size > 0 ) {
29194b212c2SPaul Mackerras 		printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size);
29294b212c2SPaul Mackerras 		initrd.addr = try_claim(initrd.size);
29394b212c2SPaul Mackerras 		if (initrd.addr == 0) {
29494b212c2SPaul Mackerras 			printf("Can't allocate memory for initial ramdisk !\n\r");
29594b212c2SPaul Mackerras 			exit();
29694b212c2SPaul Mackerras 		}
29794b212c2SPaul Mackerras 		a1 = initrd.addr;
29894b212c2SPaul Mackerras 		a2 = initrd.size;
29994b212c2SPaul Mackerras 		printf("initial ramdisk moving 0x%lx <- 0x%lx (0x%lx bytes)\n\r",
30094b212c2SPaul Mackerras 		       initrd.addr, (unsigned long)_initrd_start, initrd.size);
30194b212c2SPaul Mackerras 		memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size);
30294b212c2SPaul Mackerras 		printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd.addr));
30394b212c2SPaul Mackerras 	}
30494b212c2SPaul Mackerras 
30594b212c2SPaul Mackerras 	/* Eventually gunzip the kernel */
30694b212c2SPaul Mackerras 	if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
30794b212c2SPaul Mackerras 		printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
30894b212c2SPaul Mackerras 		       vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
30994b212c2SPaul Mackerras 		len = vmlinuz.size;
31094b212c2SPaul Mackerras 		gunzip((void *)vmlinux.addr, vmlinux.memsize,
31194b212c2SPaul Mackerras 			(unsigned char *)vmlinuz.addr, &len);
31294b212c2SPaul Mackerras 		printf("done 0x%lx bytes\n\r", len);
31394b212c2SPaul Mackerras 	} else {
31494b212c2SPaul Mackerras 		memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size);
31594b212c2SPaul Mackerras 	}
31694b212c2SPaul Mackerras 
317*30d8caf7Smostrows@watson.ibm.com 	export_cmdline(chosen_handle);
318*30d8caf7Smostrows@watson.ibm.com 
31994b212c2SPaul Mackerras 	/* Skip over the ELF header */
32094b212c2SPaul Mackerras #ifdef DEBUG
32194b212c2SPaul Mackerras 	printf("... skipping 0x%lx bytes of ELF header\n\r",
32294b212c2SPaul Mackerras 			elfoffset);
32394b212c2SPaul Mackerras #endif
32494b212c2SPaul Mackerras 	vmlinux.addr += elfoffset;
32594b212c2SPaul Mackerras 
32694b212c2SPaul Mackerras 	flush_cache((void *)vmlinux.addr, vmlinux.size);
32794b212c2SPaul Mackerras 
32894b212c2SPaul Mackerras 	kernel_entry = (kernel_entry_t)vmlinux.addr;
32994b212c2SPaul Mackerras #ifdef DEBUG
33094b212c2SPaul Mackerras 	printf( "kernel:\n\r"
33194b212c2SPaul Mackerras 		"        entry addr = 0x%lx\n\r"
33294b212c2SPaul Mackerras 		"        a1         = 0x%lx,\n\r"
33394b212c2SPaul Mackerras 		"        a2         = 0x%lx,\n\r"
33494b212c2SPaul Mackerras 		"        prom       = 0x%lx,\n\r"
33594b212c2SPaul Mackerras 		"        bi_recs    = 0x%lx,\n\r",
33694b212c2SPaul Mackerras 		(unsigned long)kernel_entry, a1, a2,
33794b212c2SPaul Mackerras 		(unsigned long)prom, NULL);
33894b212c2SPaul Mackerras #endif
33994b212c2SPaul Mackerras 
34094b212c2SPaul Mackerras 	kernel_entry(a1, a2, prom, NULL);
34194b212c2SPaul Mackerras 
34294b212c2SPaul Mackerras 	printf("Error: Linux kernel returned to zImage bootloader!\n\r");
34394b212c2SPaul Mackerras 
34494b212c2SPaul Mackerras 	exit();
34594b212c2SPaul Mackerras }
34694b212c2SPaul Mackerras 
347