linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] [PowerPC] Support For Initrd Loaded Into Highmem
  2009-05-17 16:44 [PATCH] [PowerPC] Support For Initrd Loaded Into Highmem Konstantin Baydarov
@ 2009-05-17 13:34 ` Wolfgang Denk
  2009-05-17 21:56   ` Benjamin Herrenschmidt
  2009-05-17 21:55 ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 4+ messages in thread
From: Wolfgang Denk @ 2009-05-17 13:34 UTC (permalink / raw)
  To: Konstantin Baydarov; +Cc: Kumar Gala, linuxppc-dev, linux-kernel

Dear Konstantin Baydarov,

In message <4A103EDF.7050108@ru.mvista.com> you wrote:
> 
>   It turned out that:
> PPC uBoot always loads initrd image at the highest RAM address. So if board has

Please read the documentation, for example the U-Boot  README  -  pay
speicial  attention  to  the section that discusses the "initrd_high"
envrionment variable.

>   How Solved:
> Code was added that checks if initrd is in the highmem and relocates initrd
> into lowmem if required.

I don't think this is needed. Just don't load the ramdisk to highmem
in the first place.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
How come everyone's going so slow if it's called rush hour?

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] [PowerPC] Support For Initrd Loaded Into Highmem
@ 2009-05-17 16:44 Konstantin Baydarov
  2009-05-17 13:34 ` Wolfgang Denk
  2009-05-17 21:55 ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 4+ messages in thread
From: Konstantin Baydarov @ 2009-05-17 16:44 UTC (permalink / raw)
  To: Kumar Gala, linuxppc-dev; +Cc: linux-kernel

  Hello.

  Recently I faced following issue:
On PPC targets with uBoot monitor with RAM size more than 768 Mb, boot with
initrd(rootfs image that is loaded separately from uImage) fails. Kernel crashes very early. 

  It turned out that:
PPC uBoot always loads initrd image at the highest RAM address. So if board has
sufficient amount of RAM initrd will be loaded at highmem, at address that is
bigger than CONFIG_LOWMEM_SIZE=0x30000000. Kernel cannot work with highmem
addresses directly, ioremap is required. So initrd relocation to lowmem is
required to make kernel work correctly with initrd.

Also if initrd is in the highmem, uBoot adds initrd highmem region into the
initial_boot_params->off_mem_rsvmap. This leads to kernel crash, because kernel
assumes that regions from the initial_boot_params->off_mem_rsvmap are in the
lowmem. 

  How Solved:
Code was added that checks if initrd is in the highmem and relocates initrd
into lowmem if required.

Also if initrd is in the highmem, uBoot adds initrd highmem region into the
initial_boot_params->off_mem_rsvmap. This leads to kernel crash, because kernel
assumes that regions from the initial_boot_params->off_mem_rsvmap are in the
lowmem. So patch skips initrd highmem region when kernel reserves lowmem regions
in early_reserve_mem().

  This patch is for linux-2.6.30-rc6.

Signed-off-by: Konstantin Baydarov <kbaidarov@ru.mvista.com>

Index: linux-2.6.30-rc6/arch/powerpc/kernel/prom.c
===================================================================
--- linux-2.6.30-rc6.orig/arch/powerpc/kernel/prom.c
+++ linux-2.6.30-rc6/arch/powerpc/kernel/prom.c
@@ -763,28 +763,56 @@ static int __init early_init_dt_scan_cpu
 	return 0;
 }
 
+unsigned long orig_initrd_start, orig_initrd_end;
+int need_reloc_initrd = 0;
+static int need_to_fix_reserve_map = 0;
 #ifdef CONFIG_BLK_DEV_INITRD
 static void __init early_init_dt_check_for_initrd(unsigned long node)
 {
-	unsigned long l;
+	unsigned long l, initrd_size;
 	u32 *prop;
 
 	DBG("Looking for initrd properties... ");
 
+	initrd_start = 0;
+	initrd_end = 0;
 	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
-	if (prop) {
-		initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+	if (!prop)
+		return;
 
-		prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
-		if (prop) {
-			initrd_end = (unsigned long)
-					__va(of_read_ulong(prop, l/4));
-			initrd_below_start_ok = 1;
-		} else {
-			initrd_start = 0;
-		}
-	}
+	orig_initrd_start = (unsigned long)(of_read_ulong(prop, l/4));
+	prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+	if (!prop)
+		return;
+
+	orig_initrd_end = (unsigned long)(of_read_ulong(prop, l/4));
+	initrd_below_start_ok = 1;
 
+#ifdef CONFIG_PPC32
+	need_to_fix_reserve_map = 1;
+	if (orig_initrd_end <= CONFIG_LOWMEM_SIZE) {
+		initrd_start = (unsigned long)__va(orig_initrd_start);
+		initrd_end = (unsigned long)__va(orig_initrd_end);
+		need_to_fix_reserve_map = 0;
+	}
+#ifdef CONFIG_HIGHMEM
+	else if (orig_initrd_start < CONFIG_LOWMEM_SIZE) {
+		/* TODO: add support for Initrd Image that is spread to
+		low and high mem */
+	} else {
+		/* Whole initrd is in highmem */
+		need_reloc_initrd = 1;
+		initrd_size = orig_initrd_end - orig_initrd_start;
+		initrd_start = CONFIG_LOWMEM_SIZE - initrd_size;
+		initrd_start &= PAGE_MASK;
+		initrd_start += KERNELBASE;
+		initrd_end = initrd_start + initrd_size;
+	}
+#endif
+#else
+	initrd_start = (unsigned long)__va(orig_initrd_start);
+	initrd_end = (unsigned long)__va(orig_initrd_end);
+#endif
 	DBG("initrd_start=0x%lx  initrd_end=0x%lx\n", initrd_start, initrd_end);
 }
 #else
@@ -1061,8 +1089,15 @@ static void __init early_reserve_mem(voi
 			/* skip if the reservation is for the blob */
 			if (base_32 == self_base && size_32 == self_size)
 				continue;
-			DBG("reserving: %x -> %x\n", base_32, size_32);
-			lmb_reserve(base_32, size_32);
+			/* Skip reserving initrd region if it's in highmem,
+			 * Because kernel assumes that regions are from lowmem.
+			 * Entry from high mem leads to kernel crash.
+			 */
+			if (!need_to_fix_reserve_map ||
+				(base_32 != orig_initrd_start)) {
+				DBG("reserving: %x -> %x\n", base_32, size_32);
+				lmb_reserve(base_32, size_32);
+			}
 		}
 		return;
 	}
@@ -1072,8 +1107,15 @@ static void __init early_reserve_mem(voi
 		size = *(reserve_map++);
 		if (size == 0)
 			break;
-		DBG("reserving: %llx -> %llx\n", base, size);
-		lmb_reserve(base, size);
+		/* Skip reserving initrd region if it's in highmem,
+		 * Because kernel assumes that regions are from lowmem.
+		 * Entry from high mem leads to kernel crash.
+		 */
+		if (!need_to_fix_reserve_map ||
+			(base != orig_initrd_start)) {
+			DBG("reserving: %llx -> %llx\n", base, size);
+			lmb_reserve(base, size);
+		}
 	}
 }
 
Index: linux-2.6.30-rc6/arch/powerpc/kernel/setup-common.c
===================================================================
--- linux-2.6.30-rc6.orig/arch/powerpc/kernel/setup-common.c
+++ linux-2.6.30-rc6/arch/powerpc/kernel/setup-common.c
@@ -335,6 +335,46 @@ struct seq_operations cpuinfo_op = {
 	.show =	show_cpuinfo,
 };
 
+#if defined (CONFIG_BLK_DEV_INITRD) && (CONFIG_PPC32)
+extern unsigned long orig_initrd_start, orig_initrd_end;
+extern int need_reloc_initrd;
+
+/**
+ * relocate_initrd - if initrd is loaded into highmem, relocate it
+ * to lowmem.
+ */
+static void relocate_initrd(void)
+{
+	unsigned long src = orig_initrd_start;
+	unsigned long size = orig_initrd_end - orig_initrd_start;
+	char *src_ptr;
+	char *dest = (char *) initrd_start;
+
+	if (!need_reloc_initrd)
+		return;
+
+	/* Map the physical address in and copy the
+	 * data from it, in page-size chunks. */
+	while (size) {
+		src_ptr = ioremap(src, PAGE_SIZE);
+		if (src_ptr) {
+			int amount_to_copy = min(size, PAGE_SIZE);
+			memcpy(dest, src_ptr, amount_to_copy);
+			iounmap(src_ptr);
+			src += amount_to_copy;
+			dest += amount_to_copy;
+			size -= amount_to_copy;
+		} else {
+			printk(KERN_CRIT
+			       "Can't map memory to copy ramdisk\n");
+			break;
+		}
+	}
+}
+#elif defined (CONFIG_BLK_DEV_INITRD)
+#define relocate_initrd()
+#endif
+
 void __init check_for_initrd(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -345,9 +385,10 @@ void __init check_for_initrd(void)
 	 * look sensible. If not, clear initrd reference.
 	 */
 	if (is_kernel_addr(initrd_start) && is_kernel_addr(initrd_end) &&
-	    initrd_end > initrd_start)
+	    initrd_end > initrd_start) {
+		relocate_initrd();
 		ROOT_DEV = Root_RAM0;
-	else
+	} else
 		initrd_start = initrd_end = 0;
 
 	if (initrd_start)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] [PowerPC] Support For Initrd Loaded Into Highmem
  2009-05-17 16:44 [PATCH] [PowerPC] Support For Initrd Loaded Into Highmem Konstantin Baydarov
  2009-05-17 13:34 ` Wolfgang Denk
@ 2009-05-17 21:55 ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 4+ messages in thread
From: Benjamin Herrenschmidt @ 2009-05-17 21:55 UTC (permalink / raw)
  To: Konstantin Baydarov; +Cc: Kumar Gala, linuxppc-dev, linux-kernel


> Also if initrd is in the highmem, uBoot adds initrd highmem region into the
> initial_boot_params->off_mem_rsvmap. This leads to kernel crash, because kernel
> assumes that regions from the initial_boot_params->off_mem_rsvmap are in the
> lowmem. So patch skips initrd highmem region when kernel reserves lowmem regions
> in early_reserve_mem().
> 
>   This patch is for linux-2.6.30-rc6.

Fixing the reserve map isn't the right approach.

We should be able to have anything in there. It's the kernel that should
be more careful at coping if it contains things that aren't in lowmem.

Cheers,
Ben.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] [PowerPC] Support For Initrd Loaded Into Highmem
  2009-05-17 13:34 ` Wolfgang Denk
@ 2009-05-17 21:56   ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 4+ messages in thread
From: Benjamin Herrenschmidt @ 2009-05-17 21:56 UTC (permalink / raw)
  To: Wolfgang Denk; +Cc: Konstantin Baydarov, linuxppc-dev, linux-kernel


> >   How Solved:
> > Code was added that checks if initrd is in the highmem and relocates initrd
> > into lowmem if required.
> 
> I don't think this is needed. Just don't load the ramdisk to highmem
> in the first place.

Well, it does make some sense to avoid the kernel eating itself if
passed things out of lowmem in the reserve map, though Konstantin patch
doesn't fix that properly, I think it's still something to look into.

Cheers,
Ben.



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-05-17 22:01 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-05-17 16:44 [PATCH] [PowerPC] Support For Initrd Loaded Into Highmem Konstantin Baydarov
2009-05-17 13:34 ` Wolfgang Denk
2009-05-17 21:56   ` Benjamin Herrenschmidt
2009-05-17 21:55 ` Benjamin Herrenschmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).