mirror of https://github.com/ipxe/ipxe.git
[bzimage] Report exact initrd length via bzImage header
iPXE currently pads initrd images to a multiple of 4kB and inserts zero padding between images, as required by some versions of the Linux kernel. The overall length reported via the ramdisk_size field in the bzImage header includes this zero padding. This causes problems when using memdisk to load a gzip-compressed disk image. memdisk treats the ramdisk_size field as containing the exact length of the initrd image, and uses this length to locate the 8-byte gzip footer. This will generally cause memdisk to fail to decompress the disk image. Fix by reporting the exact length of the initrd image set, including any padding inserted between images but excluding any padding added at the end of the final image. Reported-by: Levente LEVAI <levail@aviatronic.hu> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/17/head
parent
e191298a1d
commit
0fac055119
|
@ -346,13 +346,24 @@ static void bzimage_parse_cpio_cmdline ( struct image *image,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Align initrd length
|
||||
*
|
||||
* @v len Length
|
||||
* @ret len Length rounded up to INITRD_ALIGN
|
||||
*/
|
||||
static inline size_t bzimage_align ( size_t len ) {
|
||||
|
||||
return ( ( len + INITRD_ALIGN - 1 ) & ~( INITRD_ALIGN - 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load initrd
|
||||
*
|
||||
* @v image bzImage image
|
||||
* @v initrd initrd image
|
||||
* @v address Address at which to load, or UNULL
|
||||
* @ret len Length of loaded image, rounded up to INITRD_ALIGN
|
||||
* @ret len Length of loaded image, excluding zero-padding
|
||||
*/
|
||||
static size_t bzimage_load_initrd ( struct image *image,
|
||||
struct image *initrd,
|
||||
|
@ -408,11 +419,10 @@ static size_t bzimage_load_initrd ( struct image *image,
|
|||
}
|
||||
offset += initrd->len;
|
||||
|
||||
/* Round up to multiple of INITRD_ALIGN and zero-pad */
|
||||
/* Zero-pad to next INITRD_ALIGN boundary */
|
||||
pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) );
|
||||
if ( address )
|
||||
memset_user ( address, offset, 0, pad_len );
|
||||
offset += pad_len;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
@ -440,6 +450,7 @@ static int bzimage_check_initrds ( struct image *image,
|
|||
|
||||
/* Calculate length */
|
||||
len += bzimage_load_initrd ( image, initrd, UNULL );
|
||||
len = bzimage_align ( len );
|
||||
|
||||
DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n",
|
||||
image, initrd, user_to_phys ( initrd->data, 0 ),
|
||||
|
@ -487,6 +498,7 @@ static void bzimage_load_initrds ( struct image *image,
|
|||
struct image *other;
|
||||
userptr_t top;
|
||||
userptr_t dest;
|
||||
size_t offset;
|
||||
size_t len;
|
||||
|
||||
/* Reshuffle initrds into desired order */
|
||||
|
@ -505,9 +517,7 @@ static void bzimage_load_initrds ( struct image *image,
|
|||
return;
|
||||
|
||||
/* Find highest usable address */
|
||||
top = userptr_add ( highest->data,
|
||||
( ( highest->len + INITRD_ALIGN - 1 ) &
|
||||
~( INITRD_ALIGN - 1 ) ) );
|
||||
top = userptr_add ( highest->data, bzimage_align ( highest->len ) );
|
||||
if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
|
||||
top = phys_to_user ( bzimg->mem_limit );
|
||||
DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
|
||||
|
@ -519,23 +529,27 @@ static void bzimage_load_initrds ( struct image *image,
|
|||
/* Calculate cumulative length of following
|
||||
* initrds (including padding).
|
||||
*/
|
||||
len = 0;
|
||||
offset = 0;
|
||||
for_each_image ( other ) {
|
||||
if ( other == initrd )
|
||||
len = 0;
|
||||
len += bzimage_load_initrd ( image, other, UNULL );
|
||||
offset = 0;
|
||||
offset += bzimage_load_initrd ( image, other, UNULL );
|
||||
offset = bzimage_align ( offset );
|
||||
}
|
||||
|
||||
/* Load initrd at this address */
|
||||
dest = userptr_add ( top, -len );
|
||||
bzimage_load_initrd ( image, initrd, dest );
|
||||
dest = userptr_add ( top, -offset );
|
||||
len = bzimage_load_initrd ( image, initrd, dest );
|
||||
|
||||
/* Record initrd location */
|
||||
if ( ! bzimg->ramdisk_image ) {
|
||||
if ( ! bzimg->ramdisk_image )
|
||||
bzimg->ramdisk_image = user_to_phys ( dest, 0 );
|
||||
bzimg->ramdisk_size = len;
|
||||
}
|
||||
bzimg->ramdisk_size = ( user_to_phys ( dest, len ) -
|
||||
bzimg->ramdisk_image );
|
||||
}
|
||||
DBGC ( image, "bzImage %p initrds at [%#08lx,%#08lx)\n",
|
||||
image, bzimg->ramdisk_image,
|
||||
( bzimg->ramdisk_image + bzimg->ramdisk_size ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue