Commit 3cc747e9 authored by Mark Bellon's avatar Mark Bellon Committed by Paul Mackerras

[PATCH] PPC64: large INITRD causes kernel not to boot

In PPC64 there are number of problems in arch/ppc64/boot/main.c that
prevent a kernel from making use of a large (greater than ~16MB) INITRD.
This is 64 bit architecture and really large INITRD images should be
possible.

Simply put the existing code has a fixed reservation (claim) address and
once the kernel plus initrd image are large enough to pass this address
all sorts of bad things occur. The fix is the dynamically establish the
first claim address above the loaded kernel plus initrd (plus some
"padding" and rounding). If PROG_START is defined this will be used as
the minimum safe address - currently known to be 0x01400000 for the
firmwares tested so far.
Signed-off-by: default avatarMark Bellon <mbellon@mvista.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent f9526785
...@@ -23,7 +23,8 @@ extern void flush_cache(void *, unsigned long); ...@@ -23,7 +23,8 @@ extern void flush_cache(void *, unsigned long);
/* Value picked to match that used by yaboot */ /* Value picked to match that used by yaboot */
#define PROG_START 0x01400000 #define PROG_START 0x01400000
#define RAM_END (256<<20) // Fixme: use OF */ #define RAM_END (512<<20) // Fixme: use OF */
#define ONE_MB 0x100000
static char *avail_ram; static char *avail_ram;
static char *begin_avail, *end_avail; static char *begin_avail, *end_avail;
...@@ -32,6 +33,7 @@ static unsigned int heap_use; ...@@ -32,6 +33,7 @@ static unsigned int heap_use;
static unsigned int heap_max; static unsigned int heap_max;
extern char _start[]; extern char _start[];
extern char _end[];
extern char _vmlinux_start[]; extern char _vmlinux_start[];
extern char _vmlinux_end[]; extern char _vmlinux_end[];
extern char _initrd_start[]; extern char _initrd_start[];
...@@ -58,13 +60,13 @@ typedef void (*kernel_entry_t)( unsigned long, ...@@ -58,13 +60,13 @@ typedef void (*kernel_entry_t)( unsigned long,
#undef DEBUG #undef DEBUG
static unsigned long claim_base = PROG_START; static unsigned long claim_base;
static unsigned long try_claim(unsigned long size) static unsigned long try_claim(unsigned long size)
{ {
unsigned long addr = 0; unsigned long addr = 0;
for(; claim_base < RAM_END; claim_base += 0x100000) { for(; claim_base < RAM_END; claim_base += ONE_MB) {
#ifdef DEBUG #ifdef DEBUG
printf(" trying: 0x%08lx\n\r", claim_base); printf(" trying: 0x%08lx\n\r", claim_base);
#endif #endif
...@@ -95,7 +97,26 @@ void start(unsigned long a1, unsigned long a2, void *promptr) ...@@ -95,7 +97,26 @@ void start(unsigned long a1, unsigned long a2, void *promptr)
if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
exit(); exit();
printf("\n\rzImage starting: loaded at 0x%x\n\r", (unsigned)_start); printf("\n\rzImage starting: loaded at 0x%lx\n\r", (unsigned long) _start);
/*
* The first available claim_base must be above the end of the
* the loaded kernel wrapper file (_start to _end includes the
* initrd image if it is present) and rounded up to a nice
* 1 MB boundary for good measure.
*/
claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
#if defined(PROG_START)
/*
* Maintain a "magic" minimum address. This keeps some older
* firmware platforms running.
*/
if (claim_base < PROG_START)
claim_base = PROG_START;
#endif
/* /*
* Now we try to claim some memory for the kernel itself * Now we try to claim some memory for the kernel itself
...@@ -105,7 +126,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr) ...@@ -105,7 +126,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr)
* size... In practice we add 1Mb, that is enough, but we should really * size... In practice we add 1Mb, that is enough, but we should really
* consider fixing the Makefile to put a _raw_ kernel in there ! * consider fixing the Makefile to put a _raw_ kernel in there !
*/ */
vmlinux_memsize += 0x100000; vmlinux_memsize += ONE_MB;
printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux_memsize); printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux_memsize);
vmlinux.addr = try_claim(vmlinux_memsize); vmlinux.addr = try_claim(vmlinux_memsize);
if (vmlinux.addr == 0) { if (vmlinux.addr == 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment