aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2010-09-17 18:24:11 -0400
committerMichal Marek <mmarek@suse.cz>2010-09-29 10:28:59 -0400
commitffe8018c3424892c9590048fc36caa6c3e0c8a76 (patch)
tree072f02441ee317679a7029be4a1905a610de683e
parent6ae64e428f74e7bacab898ef9665dda719ea6fde (diff)
initramfs: fix initramfs size calculation
The size of a built-in initramfs is calculated in init/initramfs.c by "__initramfs_end - __initramfs_start". Those symbols are defined in the linker script include/asm-generic/vmlinux.lds.h: #define INIT_RAM_FS \ . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__initramfs_start) = .; \ *(.init.ramfs) \ VMLINUX_SYMBOL(__initramfs_end) = .; If the initramfs file has an odd number of bytes, the "__initramfs_end" symbol points to an odd address, for example, the symbols in the System.map might look like: 0000000000572000 T __initramfs_start 00000000005bcd05 T __initramfs_end <-- odd address At least on s390 this causes a problem: Certain s390 instructions, especially instructions for loading addresses (larl) or branch addresses must be on even addresses. The compiler loads the symbol addresses with the "larl" instruction. This instruction sets the last bit to 0 and, therefore, for odd size files, the calculated size is one byte less than it should be: 0000000000540a9c <populate_rootfs>: 540a9c: eb cf f0 78 00 24 stmg %r12,%r15,120(%r15), 540aa2: c0 10 00 01 8a af larl %r1,572000 <__initramfs_start> 540aa8: c0 c0 00 03 e1 2e larl %r12,5bcd04 <initramfs_end> (Instead of 5bcd05) ... 540abe: 1b c1 sr %r12,%r1 To fix the problem, this patch introduces the global variable __initramfs_size, which is calculated in the "usr/initramfs_data.S" file. The populate_rootfs() function can then use the start marker of the .init.ramfs section and the value of __initramfs_size for loading the initramfs. Because the start marker and size is sufficient, the __initramfs_end symbol is no longer needed and is removed. Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Reviewed-by: WANG Cong <xiyou.wangcong@gmail.com> Acked-by: Michal Marek <mmarek@suse.cz> Acked-by: "H. Peter Anvin" <hpa@zytor.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz>
-rw-r--r--include/asm-generic/vmlinux.lds.h3
-rw-r--r--init/initramfs.c9
-rw-r--r--usr/initramfs_data.S16
3 files changed, 17 insertions, 11 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 030a954ed292..0c6387d6a6ae 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -633,7 +633,8 @@
633 . = ALIGN(PAGE_SIZE); \ 633 . = ALIGN(PAGE_SIZE); \
634 VMLINUX_SYMBOL(__initramfs_start) = .; \ 634 VMLINUX_SYMBOL(__initramfs_start) = .; \
635 *(.init.ramfs) \ 635 *(.init.ramfs) \
636 VMLINUX_SYMBOL(__initramfs_end) = .; 636 . = ALIGN(8); \
637 *(.init.ramfs.info)
637#else 638#else
638#define INIT_RAM_FS 639#define INIT_RAM_FS
639#endif 640#endif
diff --git a/init/initramfs.c b/init/initramfs.c
index 4b9c20205092..371c3da64ad3 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -483,7 +483,8 @@ static int __init retain_initrd_param(char *str)
483} 483}
484__setup("retain_initrd", retain_initrd_param); 484__setup("retain_initrd", retain_initrd_param);
485 485
486extern char __initramfs_start[], __initramfs_end[]; 486extern char __initramfs_start[];
487extern unsigned long __initramfs_size;
487#include <linux/initrd.h> 488#include <linux/initrd.h>
488#include <linux/kexec.h> 489#include <linux/kexec.h>
489 490
@@ -570,8 +571,7 @@ static void __init clean_rootfs(void)
570 571
571static int __init populate_rootfs(void) 572static int __init populate_rootfs(void)
572{ 573{
573 char *err = unpack_to_rootfs(__initramfs_start, 574 char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
574 __initramfs_end - __initramfs_start);
575 if (err) 575 if (err)
576 panic(err); /* Failed to decompress INTERNAL initramfs */ 576 panic(err); /* Failed to decompress INTERNAL initramfs */
577 if (initrd_start) { 577 if (initrd_start) {
@@ -585,8 +585,7 @@ static int __init populate_rootfs(void)
585 return 0; 585 return 0;
586 } else { 586 } else {
587 clean_rootfs(); 587 clean_rootfs();
588 unpack_to_rootfs(__initramfs_start, 588 unpack_to_rootfs(__initramfs_start, __initramfs_size);
589 __initramfs_end - __initramfs_start);
590 } 589 }
591 printk(KERN_INFO "rootfs image is not initramfs (%s)" 590 printk(KERN_INFO "rootfs image is not initramfs (%s)"
592 "; looks like an initrd\n", err); 591 "; looks like an initrd\n", err);
diff --git a/usr/initramfs_data.S b/usr/initramfs_data.S
index 49a545fea120..b9efed5e35cc 100644
--- a/usr/initramfs_data.S
+++ b/usr/initramfs_data.S
@@ -11,11 +11,7 @@
11 -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o 11 -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
12 ld -m elf_i386 -r -o built-in.o initramfs_data.o 12 ld -m elf_i386 -r -o built-in.o initramfs_data.o
13 13
14 initramfs_data.scr looks like this: 14 For including the .init.ramfs sections, see include/asm-generic/vmlinux.lds.
15SECTIONS
16{
17 .init.ramfs : { *(.data) }
18}
19 15
20 The above example is for i386 - the parameters vary from architectures. 16 The above example is for i386 - the parameters vary from architectures.
21 Eventually look up LDFLAGS_BLOB in an older version of the 17 Eventually look up LDFLAGS_BLOB in an older version of the
@@ -28,4 +24,14 @@ SECTIONS
28#include <linux/stringify.h> 24#include <linux/stringify.h>
29 25
30.section .init.ramfs,"a" 26.section .init.ramfs,"a"
27__irf_start:
31.incbin __stringify(INITRAMFS_IMAGE) 28.incbin __stringify(INITRAMFS_IMAGE)
29__irf_end:
30.section .init.ramfs.info,"a"
31.globl __initramfs_size
32__initramfs_size:
33#ifdef CONFIG_32BIT
34 .long __irf_end - __irf_start
35#else
36 .quad __irf_end - __irf_start
37#endif