Skip to contentSkip to conversation

Fix initramfs size calculation

PATCH In review Michael Holzheu 4 participants 10 messages Aug 25, 2010 – Aug 26, 2010

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 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 is 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". This instruction sets the last bit to 0, 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.xxx.S" files. The populate_rootfs() function can then use the init.ramfs section start and the value of __initramfs_size for loading the initramfs.

The patch also restructures the "usr/initramfs_data.xxx.S" files to use a common macro that includes the (compressed) initramfs file and calculates the __initramfs_size.

---
 include/asm-generic/vmlinux.lds.h |    3 +-
 init/initramfs.c                  |    9 +++-----
 usr/initramfs_data.S              |   32 +---------------------------
 usr/initramfs_data.bz2.S          |   31 +---------------------------
 usr/initramfs_data.gz.S           |   31 +---------------------------
 usr/initramfs_data.h              |   42 ++++++++++++++++++++++++++++++++++++++
 usr/initramfs_data.lzma.S         |   31 +---------------------------
 7 files changed, 56 insertions(+), 123 deletions(-)
include/asm-generic/vmlinux.lds.h +2 -1
@@ -629,7 +629,8 @@
 	. = ALIGN(PAGE_SIZE);						\
 	VMLINUX_SYMBOL(__initramfs_start) = .;				\
 	*(.init.ramfs)							\
-	VMLINUX_SYMBOL(__initramfs_end) = .;
+	. = ALIGN(8);							\
+	*(.init.ramfs.info)
 #else
 #define INIT_RAM_FS
 #endif
init/initramfs.c +4 -5
@@ -483,7 +483,8 @@ static int __init retain_initrd_param(ch
 }
 __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/kexec.h>
 
@@ -570,8 +571,7 @@ static void __init clean_rootfs(void)
 
 static int __init populate_rootfs(void)
 {
-	char *err = unpack_to_rootfs(__initramfs_start,
-			 __initramfs_end - __initramfs_start);
+	char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
 	if (err)
 		panic(err);	/* Failed to decompress INTERNAL initramfs */
 	if (initrd_start) {
@@ -585,8 +585,7 @@ static int __init populate_rootfs(void)
 			return 0;
 		} else {
 			clean_rootfs();
-			unpack_to_rootfs(__initramfs_start,
-				 __initramfs_end - __initramfs_start);
+			unpack_to_rootfs(__initramfs_start, __initramfs_size);
 		}
 		printk(KERN_INFO "rootfs image is not initramfs (%s)"
 				"; looks like an initrd\n", err);
usr/initramfs_data.S +2 -30
@@ -1,30 +1,2 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio"
-
+#include "initramfs_data.h"
+initramfs_inc "usr/initramfs_data.cpio";
usr/initramfs_data.bz2.S +2 -29
@@ -1,29 +1,2 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio.bz2"
+#include "initramfs_data.h"
+initramfs_inc "usr/initramfs_data.cpio.bz2";
usr/initramfs_data.gz.S +2 -29
@@ -1,29 +1,2 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio.gz"
+#include "initramfs_data.h"
+initramfs_inc "usr/initramfs_data.cpio.gz";
usr/initramfs_data.h new file +42 -0

42 lines not on this page · raw message

usr/initramfs_data.lzma.S +2 -29
@@ -1,29 +1,2 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio.lzma"
+#include "initramfs_data.h"
+initramfs_inc "usr/initramfs_data.cpio.lzma";
#1 lore raw
Quoted 10 lines · Michael Holzheu

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) = .;
Quoted 8 lines

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 is a problem:

Another way to fix this could be to align . to an even address like this:

Quoted 4 lines
#define INIT_RAM_FS                                                     \
        . = ALIGN(PAGE_SIZE);                                           \
        VMLINUX_SYMBOL(__initramfs_start) = .;                          \
        *(.init.ramfs)                                                  \
          . = ALIGN(32);                                                  \
Quoted 2 lines
        VMLINUX_SYMBOL(__initramfs_end) = .;

32 was selected as this is what we will introduce as the default alignment in linker scripts anyway.

This I guess is a problem we have had some time and a minimal fix is easier to have backported by the stable team.

Quoted 3 lines

The patch also restructures the "usr/initramfs_data.xxx.S" files to use a common macro that includes the (compressed) initramfs file and calculates the __initramfs_size.

I like this anyway. Could you do this as a separate patch?

Sam

#2 lore raw

Sam,

I have work together with Michael on this patch... see my comments below

Quoted 9 lines · Sam Ravnborg

On Wed, Aug 25, 2010 at 05:57:12PM +0200, Michael Holzheu wrote:

Another way to fix this could be to align . to an even address like this:

Quoted 4 lines
#define INIT_RAM_FS                                                     \
        . = ALIGN(PAGE_SIZE);                                           \
        VMLINUX_SYMBOL(__initramfs_start) = .;                          \
        *(.init.ramfs)                                                  \
          . = ALIGN(32);                                                  \
Quoted 8 lines
Quoted 2 lines
        VMLINUX_SYMBOL(__initramfs_end) = .;

32 was selected as this is what we will introduce as the default alignment in linker scripts anyway.

This I guess is a problem we have had some time and a minimal fix is easier to have backported by the stable team.

The first thought was similar but using ALIGN(2). However, the current implementation of populate_rootfs() passes the calculated size to the decompress functions. If __initramfs_end is aligned, the resulting size might be greater than the real size of the initramfs.
So I guess this might also cause problems.

Quoted 4 lines
Quoted 3 lines

The patch also restructures the "usr/initramfs_data.xxx.S" files to use a common macro that includes the (compressed) initramfs file and calculates the __initramfs_size.

I like this anyway. Could you do this as a separate patch?

I think that Michael or me could do this.

Kind regards,
Hendrik

#3 lore raw
Quoted 20 lines · Hendrik Brueckner

Sam,

I have work together with Michael on this patch... see my comments below

Quoted 15 lines · Sam Ravnborg

On Wed, Aug 25, 2010 at 05:57:12PM +0200, Michael Holzheu wrote:

Another way to fix this could be to align . to an even address like this:

Quoted 4 lines
#define INIT_RAM_FS                                                     \
        . = ALIGN(PAGE_SIZE);                                           \
        VMLINUX_SYMBOL(__initramfs_start) = .;                          \
        *(.init.ramfs)                                                  \
          . = ALIGN(32);                                                  \
Quoted 2 lines
        VMLINUX_SYMBOL(__initramfs_end) = .;

32 was selected as this is what we will introduce as the default alignment in linker scripts anyway.

Quoted 8 lines
Quoted 2 lines

This I guess is a problem we have had some time and a minimal fix is easier to have backported by the stable team.

The first thought was similar but using ALIGN(2). However, the current implementation of populate_rootfs() passes the calculated size to the decompress functions. If __initramfs_end is aligned, the resulting size might be greater than the real size of the initramfs.
So I guess this might also cause problems.

Another variant could be to explicit add alignment in the .S files
so the section is always aligned to a even byte boundary (or maybe 32 byte boundary).

That should also cover the above case.

Sam

#4 lore raw

Hello Sam,

Quoted 24 lines · Sam Ravnborg
Quoted 23 lines · Hendrik Brueckner

Sam,

I have work together with Michael on this patch... see my comments below

Quoted 17 lines · Sam Ravnborg

On Wed, Aug 25, 2010 at 05:57:12PM +0200, Michael Holzheu wrote:

Another way to fix this could be to align . to an even address like this:

Quoted 4 lines
#define INIT_RAM_FS                                                     \
        . = ALIGN(PAGE_SIZE);                                           \
        VMLINUX_SYMBOL(__initramfs_start) = .;                          \
        *(.init.ramfs)                                                  \
          . = ALIGN(32);                                                  \
Quoted 2 lines
        VMLINUX_SYMBOL(__initramfs_end) = .;

32 was selected as this is what we will introduce as the default alignment in linker scripts anyway.

This I guess is a problem we have had some time and a minimal fix is easier to have backported by the stable team.

Quoted 7 lines
Quoted 5 lines

The first thought was similar but using ALIGN(2). However, the current implementation of populate_rootfs() passes the calculated size to the decompress functions. If __initramfs_end is aligned, the resulting size might be greater than the real size of the initramfs.
So I guess this might also cause problems.

Another variant could be to explicit add alignment in the .S files
so the section is always aligned to a even byte boundary (or maybe 32 byte boundary).

Then still the unpack_to_rootfs() function will not get the correct size of the compressed file, because "__initramfs_end - __initramfs_start" can be bigger than the real file size depending on the used the alignment. I would assume that not all decompression functions will work, if a bigger value is passed to decompress_method().

Michael

#5 lore raw

PATCH v2 1/2 initramfs: Generalize initramfs_data.xxx.S variants

In reply to Sam Ravnborg

Remove initramfs_data.{lzo,lzma,gz,bz2}.S variants and use a common implementation in initramfs_data.S. The common implementation expects the file name of the initramfs to be defined in INITRAMFS_IMAGE.

Change the Makefile to set the INITRAMFS_IMAGE define symbol according to the selected compression method.

---
 usr/Makefile              |    6 ++++--
 usr/initramfs_data.S      |    5 +++--
 usr/initramfs_data.bz2.S  |   29 -----------------------------
 usr/initramfs_data.gz.S   |   29 -----------------------------
 usr/initramfs_data.lzma.S |   29 -----------------------------
 usr/initramfs_data.lzo.S  |   29 -----------------------------
 6 files changed, 7 insertions(+), 120 deletions(-)
usr/Makefile +4 -2
@@ -18,13 +18,15 @@ suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZ
 # Lzo
 suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZO)   = .lzo
 
+AFLAGS_initramfs_data.o += -DINITRAMFS_IMAGE="usr/initramfs_data.cpio$(suffix_y)"
+
 # Generate builtin.o based on initramfs_data.o
-obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data$(suffix_y).o
+obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data.o
 
 # initramfs_data.o contains the compressed initramfs_data.cpio image.
 # The image is included using .incbin, a dependency which is not
 # tracked automatically.
-$(obj)/initramfs_data$(suffix_y).o: $(obj)/initramfs_data.cpio$(suffix_y) FORCE
+$(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio$(suffix_y) FORCE
 
 #####
 # Generate the initramfs cpio archive
usr/initramfs_data.S +3 -2
@@ -25,6 +25,7 @@ SECTIONS
   in the ELF header, as required by certain architectures.
 */
 
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio"
+#include <linux/stringify.h>
 
+.section .init.ramfs,"a"
+.incbin __stringify(INITRAMFS_IMAGE)
usr/initramfs_data.bz2.S deleted +0 -29
@@ -1,29 +0,0 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio.bz2"
usr/initramfs_data.gz.S deleted +0 -29
@@ -1,29 +0,0 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio.gz"
usr/initramfs_data.lzma.S deleted +0 -29
@@ -1,29 +0,0 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio.lzma"
usr/initramfs_data.lzo.S deleted +0 -29
@@ -1,29 +0,0 @@
-/*
-  initramfs_data includes the compressed binary that is the
-  filesystem used for early user space.
-  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
-  released on 2001-07-14) dit not support .incbin.
-  If you are forced to use older binutils than that then the
-  following trick can be applied to create the resulting binary:
-
-
-  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
-  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
-
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
-
-  The above example is for i386 - the parameters vary from architectures.
-  Eventually look up LDFLAGS_BLOB in an older version of the
-  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
-
-  Using .incbin has the advantage over ld that the correct flags are set
-  in the ELF header, as required by certain architectures.
-*/
-
-.section .init.ramfs,"a"
-.incbin "usr/initramfs_data.cpio.lzo"
#6 lore raw

v2 cover initramfs: Cleanup and fix initramfs size calculation

In reply to Sam Ravnborg
Quoted 6 lines · Sam Ravnborg
Quoted 3 lines · Michael Holzheu

The patch also restructures the "usr/initramfs_data.xxx.S" files to use a common macro that includes the (compressed) initramfs file and calculates the __initramfs_size.

I like this anyway. Could you do this as a separate patch?

Done ;-)

The first patch in this series introduces a common initramfs_data.S file that is shared by the compression variants. The second patch adds the new initramfs size calculation proposed in the initial patch.
See the patch description for more details.

Kind regards,
Hendrik

#7 lore raw

PATCH v2 2/2 initramfs: Fix initramfs size calculation

In reply to Sam Ravnborg

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.

---
 include/asm-generic/vmlinux.lds.h |    3 ++-
 init/initramfs.c                  |    9 ++++-----
 usr/initramfs_data.S              |   16 +++++++++++-----
 3 files changed, 17 insertions(+), 11 deletions(-)
include/asm-generic/vmlinux.lds.h +2 -1
@@ -629,7 +629,8 @@
 	. = ALIGN(PAGE_SIZE);						\
 	VMLINUX_SYMBOL(__initramfs_start) = .;				\
 	*(.init.ramfs)							\
-	VMLINUX_SYMBOL(__initramfs_end) = .;
+	. = ALIGN(8);							\
+	*(.init.ramfs.info)
 #else
 #define INIT_RAM_FS
 #endif
init/initramfs.c +4 -5
@@ -483,7 +483,8 @@ static int __init retain_initrd_param(ch
 }
 __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/kexec.h>
 
@@ -570,8 +571,7 @@ static void __init clean_rootfs(void)
 
 static int __init populate_rootfs(void)
 {
-	char *err = unpack_to_rootfs(__initramfs_start,
-			 __initramfs_end - __initramfs_start);
+	char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
 	if (err)
 		panic(err);	/* Failed to decompress INTERNAL initramfs */
 	if (initrd_start) {
@@ -585,8 +585,7 @@ static int __init populate_rootfs(void)
 			return 0;
 		} else {
 			clean_rootfs();
-			unpack_to_rootfs(__initramfs_start,
-				 __initramfs_end - __initramfs_start);
+			unpack_to_rootfs(__initramfs_start, __initramfs_size);
 		}
 		printk(KERN_INFO "rootfs image is not initramfs (%s)"
 				"; looks like an initrd\n", err);
usr/initramfs_data.S +11 -5
@@ -11,11 +11,7 @@
   -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
    ld -m elf_i386  -r -o built-in.o initramfs_data.o
 
-  initramfs_data.scr looks like this:
-SECTIONS
-{
-       .init.ramfs : { *(.data) }
-}
+  For including the .init.ramfs sections, see include/asm-generic/vmlinux.lds.
 
   The above example is for i386 - the parameters vary from architectures.
   Eventually look up LDFLAGS_BLOB in an older version of the
@@ -28,4 +24,14 @@ SECTIONS
 #include <linux/stringify.h>
 
 .section .init.ramfs,"a"
+__irf_start:
 .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
#8 lore raw
In reply to Michael Holzheu
Quoted 2 lines · Michael Holzheu

Certain s390 instructions, especially instructions for loading addresses (larl) or branch addresses must be on even addresses.

I have to admit to finding this fairly disturbing, as this is likely to come up again and again. Is there any way to tell gcc (e.g. with an alignment attribute) that a particular symbol is not safe to be loaded with larl?

-hpa

#9 lore raw

Hello Peter,

Quoted 8 lines · H. Peter Anvin
Quoted 2 lines · Michael Holzheu

Certain s390 instructions, especially instructions for loading addresses (larl) or branch addresses must be on even addresses.

I have to admit to finding this fairly disturbing, as this is likely to come up again and again. Is there any way to tell gcc (e.g. with an alignment attribute) that a particular symbol is not safe to be loaded with larl?

I think, it is not possible the change that in the compiler. The fact that the compiler on s390 assumes that symbols are 2 byte aligned was a design decission and is part of the ABI.

Michael