diff mbox

ARM: Fix incorrect FDT initrd parameter override

Message ID 0a923e$51mtvt@icp-osb-irony-out9.iinet.net.au (mailing list archive)
State New, archived
Headers show

Commit Message

Ben Peddell Jan. 11, 2014, 12:03 a.m. UTC
Commit 65939301acdb (arm: set initrd_start/initrd_end for fdt scan)
caused the FDT initrd_start and initrd_end to override the
phys_initrd_start and phys_initrd_size set by the initrd= kernel
parameter.  With this patch initrd_start and initrd_end will be
overridden if phys_initrd_start and phys_initrd_size are set by the
kernel initrd= parameter.

Signed-off-by: Ben Peddell <klightspeed@killerwolves.net>
---
 arch/arm/mm/init.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Jason Cooper Jan. 13, 2014, 3:28 p.m. UTC | #1
Ben,

Thanks for the patch.  A few comments below.

On Sat, Jan 11, 2014 at 10:03:58AM +1000, klightspeed@killerwolves.net wrote:
> Commit 65939301acdb (arm: set initrd_start/initrd_end for fdt scan)

Thanks for including this.  We have a new tag we are using now to
incorporate this information to be included after your SoB.  I've added
it below.

> caused the FDT initrd_start and initrd_end to override the
> phys_initrd_start and phys_initrd_size set by the initrd= kernel
> parameter.  With this patch initrd_start and initrd_end will be
> overridden if phys_initrd_start and phys_initrd_size are set by the
> kernel initrd= parameter.
> 
> Signed-off-by: Ben Peddell <klightspeed@killerwolves.net>
Fixes: 65939301acdb (arm: set initrd_start/initrd_end for fdt scan)

This commit was only introduced in v3.13-rc1 so we shouldn't need the
stable tag.  Unless v3.13 drops before Russell gets a chance to merge
it.

> ---
>  arch/arm/mm/init.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index 1f7b19a..819c539 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -345,10 +345,11 @@ void __init arm_memblock_init(struct meminfo *mi,
>  #endif
>  #ifdef CONFIG_BLK_DEV_INITRD
>  	/* FDT scan will populate initrd_start */
> -	if (initrd_start) {
> +	if (initrd_start && !phys_initrd_size) {
>  		phys_initrd_start = __virt_to_phys(initrd_start);
>  		phys_initrd_size = initrd_end - initrd_start;
>  	}
> +	initrd_start = initrd_end = 0;

This line shouldn't be necessary.  Both are reset in the following hunk
below your change:

if (phys_initrd_size) {
	memblock_reserve(phys_initrd_start, phys_initrd_size);

	/* Now convert initrd to virtual addresses */
	initrd_start = __phys_to_virt(phys_initrd_start);
	initrd_end = initrd_start + phys_initrd_size;
}

With the above line removed,

Acked-by: Jason Cooper <jason@lakedaemon.net>

Please add this patch to Russell's patch tracker found at

http://www.arm.linux.org.uk/developer/patches/

thx,

Jason.
Ben Peddell Jan. 13, 2014, 9:08 p.m. UTC | #2
Patch submitted with requested changes.

On Mon, 13 Jan 2014 at 10:28:51 AM -0500, Jason Cooper wrote:
>> +	initrd_start = initrd_end = 0;
> 
> This line shouldn't be necessary.  Both are reset in the following hunk
> below your change:
> 

if (phys_initrd_size &&
    !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
	pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
	       (u64)phys_initrd_start, phys_initrd_size);
	phys_initrd_start = phys_initrd_size = 0;
}
if (phys_initrd_size &&
    memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
	pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
	       (u64)phys_initrd_start, phys_initrd_size);
	phys_initrd_start = phys_initrd_size = 0;
}

> if (phys_initrd_size) {
> 	memblock_reserve(phys_initrd_start, phys_initrd_size);
> 
> 	/* Now convert initrd to virtual addresses */
> 	initrd_start = __phys_to_virt(phys_initrd_start);
> 	initrd_end = initrd_start + phys_initrd_size;
> }

Please note that above this a check is made to ensure that
phys_initrd_start and phys_initrd_size are valid, and they are zeroed
if they are not valid.  Therefore if phys_initrd_start or 
phys_initrd_size are invalid, then initrd_start and initrd_end are not
reset.

This means that if the initrd= address is not present or is invalid
then the FDT address will be used anyway as initrd_start and 
initrd_end will not have been zeroed, and if that is invalid the
kernel will OOPS in unpack_to_rootfs():

[    0.000000] INITRD: 0xf8280040+0x000f993c is not a memory region - disabling initrd
...
[    1.316588] Trying to unpack rootfs image as initramfs...
[    1.322063] Unable to handle kernel paging request at virtual address b8280040
[    1.329334] pgd = c0004000
[    1.332118] [b8280040] *pgd=00000000
[    1.335766] Internal error: Oops: 5 [#1] ARM
[    1.340098] Modules linked in:
[    1.343232] CPU: 0 PID: 1 Comm: swapper Not tainted 3.13.0-rc7-ds211j+ #2
[    1.350072] task: c7839bc0 ti: c783a000 task.ti: c783a000
[    1.355529] PC is at unpack_to_rootfs+0xa8/0x2b0
[    1.360206] LR is at unpack_to_rootfs+0x44/0x2b0
[    1.364883] pc : [<c047c998>]    lr : [<c047c934>]    psr: 20000053
[    1.364883] sp : c783be40  ip : 000008d8  fp : 00000000
[    1.376474] r10: 00000000  r9 : 00000068  r8 : c047d020
[    1.381755] r7 : c049d068  r6 : b8280040  r5 : 000f993c  r4 : c049d068
[    1.388329] r3 : 00000000  r2 : 00000000  r1 : 00000000  r0 : c7924000
[    1.394905] Flags: nzCv  IRQs on  FIQs off  Mode SVC_32  ISA ARM  Segment kernel
[    1.402343] Control: 0005397f  Table: 00004000  DAC: 00000017
[    1.408140] Process swapper (pid: 1, stack limit = 0xc783a1c0)
[    1.414024] Stack: (0xc783be40 to 0xc783c000)
[    1.418446] be40: 00000000 c04a34fc c04d3f00 c047d020 00000000 00000000 c04d3f4c c0343368
[    1.426671] be60: c03f85f6 c04d3f50 00000000 c04a34fc c04d3f00 c047d020 00000068 c04d3f50
[    1.434897] be80: c04d3f4c c047d074 ffffffff 00000000 c04c1b5c c04fffc4 c04c1b5c c049023c
[    1.443121] bea0: 00000068 00000000 c783a038 c0343368 c041909f c783becc 00000020 c783becc
[    1.451346] bec0: 00000000 c049031c c041909f 00000000 00000020 00000005 c049bbc8 c04a34fc
[    1.459572] bee0: c04d3f00 c047d020 00000068 00000000 c783a038 c000869c c782b6a0 c00d89c0
[    1.467797] bf00: c782b700 c782b6a0 00000000 c782b6a0 c034c50c c04f7914 00000000 c00d8c5c
[    1.476023] bf20: 00000068 c060edf7 00000000 c0031dc8 60000053 c0457d84 c0457704 00000068
[    1.484247] bf40: 00000005 00000005 00000001 00000005 c049bbc8 c04a34fc c04d3f00 c04d3f00
[    1.492473] bf60: 00000068 c049bbd8 00000000 c047ab14 00000005 00000005 c047a478 c002f124
[    1.500697] bf80: 00000000 00000000 00000000 c0340fb4 00000000 00000000 00000000 00000000
[    1.508923] bfa0: 00000000 c0340fbc 00000000 c000e050 00000000 00000000 00000000 00000000
[    1.517147] bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    1.525373] bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[    1.533606] [<c047c998>] (unpack_to_rootfs+0xa8/0x2b0) from [<c047d074>] (populate_rootfs+0x54/0x224)
[    1.542873] [<c047d074>] (populate_rootfs+0x54/0x224) from [<c000869c>] (do_one_initcall+0x94/0x13c)
[    1.552055] [<c000869c>] (do_one_initcall+0x94/0x13c) from [<c047ab14>] (kernel_init_freeable+0xf8/0x1b8)
[    1.561671] [<c047ab14>] (kernel_init_freeable+0xf8/0x1b8) from [<c0340fbc>] (kernel_init+0x8/0x100)
[    1.570852] [<c0340fbc>] (kernel_init+0x8/0x100) from [<c000e050>] (ret_from_fork+0x14/0x24)
[    1.579339] Code: 1a000056 e3550000 0a000054 e1c7a1d0 (e5d63000)
[    1.585525] ---[ end trace 4e31448959d8cde7 ]---
[    1.590212] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
Jason Cooper Jan. 13, 2014, 9:28 p.m. UTC | #3
Ben,

On Tue, Jan 14, 2014 at 07:08:30AM +1000, Ben Peddell wrote:
> Patch submitted with requested changes.
> 
> On Mon, 13 Jan 2014 at 10:28:51 AM -0500, Jason Cooper wrote:
> >> +	initrd_start = initrd_end = 0;
> > 
> > This line shouldn't be necessary.  Both are reset in the following hunk
> > below your change:
> > 
> 
> if (phys_initrd_size &&
>     !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
> 	pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
> 	       (u64)phys_initrd_start, phys_initrd_size);
> 	phys_initrd_start = phys_initrd_size = 0;
> }
> if (phys_initrd_size &&
>     memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
> 	pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
> 	       (u64)phys_initrd_start, phys_initrd_size);
> 	phys_initrd_start = phys_initrd_size = 0;
> }
> 
> > if (phys_initrd_size) {
> > 	memblock_reserve(phys_initrd_start, phys_initrd_size);
> > 
> > 	/* Now convert initrd to virtual addresses */
> > 	initrd_start = __phys_to_virt(phys_initrd_start);
> > 	initrd_end = initrd_start + phys_initrd_size;
> > }
> 
> Please note that above this a check is made to ensure that
> phys_initrd_start and phys_initrd_size are valid, and they are zeroed
> if they are not valid.  Therefore if phys_initrd_start or 
> phys_initrd_size are invalid, then initrd_start and initrd_end are not
> reset.
> 
> This means that if the initrd= address is not present or is invalid
> then the FDT address will be used anyway as initrd_start and 
> initrd_end will not have been zeroed, and if that is invalid the
> kernel will OOPS in unpack_to_rootfs():

Ahhh, ok.  Thanks for the clarification.  You kept that line in the
version you submitted to Russell's patch tracker?

thx,

Jason.
Ben Peddell Jan. 13, 2014, 10:18 p.m. UTC | #4
On 14/01/2014 7:28 AM, Jason Cooper wrote:
> Ahhh, ok.  Thanks for the clarification.  You kept that line in the
> version you submitted to Russell's patch tracker?

Negative.  I'll supersede the patch with one including that line.
diff mbox

Patch

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 1f7b19a..819c539 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -345,10 +345,11 @@  void __init arm_memblock_init(struct meminfo *mi,
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* FDT scan will populate initrd_start */
-	if (initrd_start) {
+	if (initrd_start && !phys_initrd_size) {
 		phys_initrd_start = __virt_to_phys(initrd_start);
 		phys_initrd_size = initrd_end - initrd_start;
 	}
+	initrd_start = initrd_end = 0;
 	if (phys_initrd_size &&
 	    !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
 		pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",