Commit ffe8018c authored by Hendrik Brueckner's avatar Hendrik Brueckner Committed by Michal Marek

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: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: default avatarHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: default avatarWANG Cong <xiyou.wangcong@gmail.com>
Acked-by: default avatarMichal Marek <mmarek@suse.cz>
Acked-by: default avatar"H. Peter Anvin" <hpa@zytor.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarMichal Marek <mmarek@suse.cz>
parent 6ae64e42
...@@ -633,7 +633,8 @@ ...@@ -633,7 +633,8 @@
. = ALIGN(PAGE_SIZE); \ . = ALIGN(PAGE_SIZE); \
VMLINUX_SYMBOL(__initramfs_start) = .; \ VMLINUX_SYMBOL(__initramfs_start) = .; \
*(.init.ramfs) \ *(.init.ramfs) \
VMLINUX_SYMBOL(__initramfs_end) = .; . = ALIGN(8); \
*(.init.ramfs.info)
#else #else
#define INIT_RAM_FS #define INIT_RAM_FS
#endif #endif
......
...@@ -483,7 +483,8 @@ static int __init retain_initrd_param(char *str) ...@@ -483,7 +483,8 @@ static int __init retain_initrd_param(char *str)
} }
__setup("retain_initrd", retain_initrd_param); __setup("retain_initrd", retain_initrd_param);
extern char __initramfs_start[], __initramfs_end[]; extern char __initramfs_start[];
extern unsigned long __initramfs_size;
#include <linux/initrd.h> #include <linux/initrd.h>
#include <linux/kexec.h> #include <linux/kexec.h>
...@@ -570,8 +571,7 @@ static void __init clean_rootfs(void) ...@@ -570,8 +571,7 @@ static void __init clean_rootfs(void)
static int __init populate_rootfs(void) static int __init populate_rootfs(void)
{ {
char *err = unpack_to_rootfs(__initramfs_start, char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
__initramfs_end - __initramfs_start);
if (err) if (err)
panic(err); /* Failed to decompress INTERNAL initramfs */ panic(err); /* Failed to decompress INTERNAL initramfs */
if (initrd_start) { if (initrd_start) {
...@@ -585,8 +585,7 @@ static int __init populate_rootfs(void) ...@@ -585,8 +585,7 @@ static int __init populate_rootfs(void)
return 0; return 0;
} else { } else {
clean_rootfs(); clean_rootfs();
unpack_to_rootfs(__initramfs_start, unpack_to_rootfs(__initramfs_start, __initramfs_size);
__initramfs_end - __initramfs_start);
} }
printk(KERN_INFO "rootfs image is not initramfs (%s)" printk(KERN_INFO "rootfs image is not initramfs (%s)"
"; looks like an initrd\n", err); "; looks like an initrd\n", err);
......
...@@ -11,11 +11,7 @@ ...@@ -11,11 +11,7 @@
-T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
ld -m elf_i386 -r -o built-in.o initramfs_data.o ld -m elf_i386 -r -o built-in.o initramfs_data.o
initramfs_data.scr looks like this: For including the .init.ramfs sections, see include/asm-generic/vmlinux.lds.
SECTIONS
{
.init.ramfs : { *(.data) }
}
The above example is for i386 - the parameters vary from architectures. The above example is for i386 - the parameters vary from architectures.
Eventually look up LDFLAGS_BLOB in an older version of the Eventually look up LDFLAGS_BLOB in an older version of the
...@@ -28,4 +24,14 @@ SECTIONS ...@@ -28,4 +24,14 @@ SECTIONS
#include <linux/stringify.h> #include <linux/stringify.h>
.section .init.ramfs,"a" .section .init.ramfs,"a"
__irf_start:
.incbin __stringify(INITRAMFS_IMAGE) .incbin __stringify(INITRAMFS_IMAGE)
__irf_end:
.section .init.ramfs.info,"a"
.globl __initramfs_size
__initramfs_size:
#ifdef CONFIG_32BIT
.long __irf_end - __irf_start
#else
.quad __irf_end - __irf_start
#endif
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