]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[bzimage] Align initrd images to page boundary
authorMichael Brown <mcb30@ipxe.org>
Wed, 5 Jun 2013 13:01:40 +0000 (14:01 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 5 Jun 2013 13:11:43 +0000 (14:11 +0100)
Some versions of Linux apparently complain if initrds are not aligned
to a page boundary.  Fix by changing INITRD_ALIGN from 4 bytes to 4096
bytes.

The amount of padding at the end of each initrd will now often be
sufficient to allow the cpio header to be prepended without crossing
an alignment boundary.  The final location of the initrd may therefore
end up being slightly higher than the post-shuffle location.
bzimage_load_initrd() must therefore now copy the initrd body prior to
copying the cpio header, otherwise the start of the initrd body may be
overwritten by the cpio header.  (Note that the guarantee that an
initrd will never need to overwrite an initrd at a higher location
still holds, since the overall length of each initrd cannot decrease
as a result of adding a cpio header.)

Reported-by: Dave Hansen <dave@sr71.net>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/image/bzimage.c
src/arch/i386/include/initrd.h

index 12be17793fbedf0d92b16f411e289d75164fd25c..3b484b17409f1bb4c733138eace48be593a64b56 100644 (file)
@@ -360,7 +360,7 @@ static size_t bzimage_load_initrd ( struct image *image,
        char *filename = initrd->cmdline;
        char *cmdline;
        struct cpio_header cpio;
-        size_t offset = 0;
+       size_t offset;
        size_t name_len;
        size_t pad_len;
 
@@ -368,7 +368,7 @@ static size_t bzimage_load_initrd ( struct image *image,
        if ( initrd == image )
                return 0;
 
-       /* Create cpio header before non-prebuilt images */
+       /* Create cpio header for non-prebuilt images */
        if ( filename && filename[0] ) {
                cmdline = strchr ( filename, ' ' );
                name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
@@ -383,24 +383,20 @@ static size_t bzimage_load_initrd ( struct image *image,
                        bzimage_parse_cpio_cmdline ( image, &cpio,
                                                     ( cmdline + 1 /* ' ' */ ));
                }
-               if ( address ) {
-                       copy_to_user ( address, offset, &cpio,
-                                      sizeof ( cpio ) );
-               }
-               offset += sizeof ( cpio );
-               if ( address ) {
-                       memset_user ( address, offset, 0, name_len );
-                       copy_to_user ( address, offset, filename,
-                                      ( name_len - 1 /* NUL (or space) */ ) );
-               }
-               offset += name_len;
-               offset = ( ( offset + 0x03 ) & ~0x03 );
+               offset = ( ( sizeof ( cpio ) + name_len + 0x03 ) & ~0x03 );
+       } else {
+               offset = 0;
        }
 
-       /* Copy in initrd image body */
-       if ( address )
-               memmove_user ( address, offset, initrd->data, 0, initrd->len );
+       /* Copy in initrd image body (and cpio header if applicable) */
        if ( address ) {
+               memmove_user ( address, offset, initrd->data, 0, initrd->len );
+               if ( offset ) {
+                       memset_user ( address, 0, 0, offset );
+                       copy_to_user ( address, 0, &cpio, sizeof ( cpio ) );
+                       copy_to_user ( address, sizeof ( cpio ), filename,
+                                      ( name_len - 1 /* NUL (or space) */ ) );
+               }
                DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
                       "%s%s\n", image, initrd, user_to_phys ( address, 0 ),
                       user_to_phys ( address, offset ),
index c25d0924b662735fe53e78208799274f54d3ee95..a5659f43c1298156985bb8259b8ae91356215738 100644 (file)
@@ -13,9 +13,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 /** Minimum alignment for initrds
  *
- * Chosen to maximise memcpy() speeds
+ * Some versions of Linux complain about initrds that are not
+ * page-aligned.
  */
-#define INITRD_ALIGN 4
+#define INITRD_ALIGN 4096
 
 /** Minimum free space required to reshuffle initrds
  *