Browse Source

[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>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
0fac055119
1 changed files with 28 additions and 14 deletions
  1. 28
    14
      src/arch/i386/image/bzimage.c

+ 28
- 14
src/arch/i386/image/bzimage.c View File

@@ -346,13 +346,24 @@ static void bzimage_parse_cpio_cmdline ( struct image *image,
346 346
 	}
347 347
 }
348 348
 
349
+/**
350
+ * Align initrd length
351
+ *
352
+ * @v len		Length
353
+ * @ret len		Length rounded up to INITRD_ALIGN
354
+ */
355
+static inline size_t bzimage_align ( size_t len ) {
356
+
357
+	return ( ( len + INITRD_ALIGN - 1 ) & ~( INITRD_ALIGN - 1 ) );
358
+}
359
+
349 360
 /**
350 361
  * Load initrd
351 362
  *
352 363
  * @v image		bzImage image
353 364
  * @v initrd		initrd image
354 365
  * @v address		Address at which to load, or UNULL
355
- * @ret len		Length of loaded image, rounded up to INITRD_ALIGN
366
+ * @ret len		Length of loaded image, excluding zero-padding
356 367
  */
357 368
 static size_t bzimage_load_initrd ( struct image *image,
358 369
 				    struct image *initrd,
@@ -408,11 +419,10 @@ static size_t bzimage_load_initrd ( struct image *image,
408 419
 	}
409 420
 	offset += initrd->len;
410 421
 
411
-	/* Round up to multiple of INITRD_ALIGN and zero-pad */
422
+	/* Zero-pad to next INITRD_ALIGN boundary */
412 423
 	pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) );
413 424
 	if ( address )
414 425
 		memset_user ( address, offset, 0, pad_len );
415
-	offset += pad_len;
416 426
 
417 427
 	return offset;
418 428
 }
@@ -440,6 +450,7 @@ static int bzimage_check_initrds ( struct image *image,
440 450
 
441 451
 		/* Calculate length */
442 452
 		len += bzimage_load_initrd ( image, initrd, UNULL );
453
+		len = bzimage_align ( len );
443 454
 
444 455
 		DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n",
445 456
 		       image, initrd, user_to_phys ( initrd->data, 0 ),
@@ -487,6 +498,7 @@ static void bzimage_load_initrds ( struct image *image,
487 498
 	struct image *other;
488 499
 	userptr_t top;
489 500
 	userptr_t dest;
501
+	size_t offset;
490 502
 	size_t len;
491 503
 
492 504
 	/* Reshuffle initrds into desired order */
@@ -505,9 +517,7 @@ static void bzimage_load_initrds ( struct image *image,
505 517
 		return;
506 518
 
507 519
 	/* Find highest usable address */
508
-	top = userptr_add ( highest->data,
509
-			    ( ( highest->len + INITRD_ALIGN - 1 ) &
510
-			      ~( INITRD_ALIGN - 1 ) ) );
520
+	top = userptr_add ( highest->data, bzimage_align ( highest->len ) );
511 521
 	if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
512 522
 		top = phys_to_user ( bzimg->mem_limit );
513 523
 	DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
@@ -519,23 +529,27 @@ static void bzimage_load_initrds ( struct image *image,
519 529
 		/* Calculate cumulative length of following
520 530
 		 * initrds (including padding).
521 531
 		 */
522
-		len = 0;
532
+		offset = 0;
523 533
 		for_each_image ( other ) {
524 534
 			if ( other == initrd )
525
-				len = 0;
526
-			len += bzimage_load_initrd ( image, other, UNULL );
535
+				offset = 0;
536
+			offset += bzimage_load_initrd ( image, other, UNULL );
537
+			offset = bzimage_align ( offset );
527 538
 		}
528 539
 
529 540
 		/* Load initrd at this address */
530
-		dest = userptr_add ( top, -len );
531
-		bzimage_load_initrd ( image, initrd, dest );
541
+		dest = userptr_add ( top, -offset );
542
+		len = bzimage_load_initrd ( image, initrd, dest );
532 543
 
533 544
 		/* Record initrd location */
534
-		if ( ! bzimg->ramdisk_image ) {
545
+		if ( ! bzimg->ramdisk_image )
535 546
 			bzimg->ramdisk_image = user_to_phys ( dest, 0 );
536
-			bzimg->ramdisk_size = len;
537
-		}
547
+		bzimg->ramdisk_size = ( user_to_phys ( dest, len ) -
548
+					bzimg->ramdisk_image );
538 549
 	}
550
+	DBGC ( image, "bzImage %p initrds at [%#08lx,%#08lx)\n",
551
+	       image, bzimg->ramdisk_image,
552
+	       ( bzimg->ramdisk_image + bzimg->ramdisk_size ) );
539 553
 }
540 554
 
541 555
 /**

Loading…
Cancel
Save